Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r47080:ba3e8ce278bc Date: 2011-09-05 14:16 +0200 http://bitbucket.org/pypy/pypy/changeset/ba3e8ce278bc/
Log: (fenrrir) Rewrite using the _continuation module. diff --git a/lib_pypy/stackless.py b/lib_pypy/stackless.py --- a/lib_pypy/stackless.py +++ b/lib_pypy/stackless.py @@ -4,121 +4,124 @@ Please refer to their documentation. """ -DEBUG = True - -def dprint(*args): - for arg in args: - print arg, - print import traceback -import sys +import _continuation +from functools import partial + +class TaskletExit(Exception): + pass + +CoroutineExit = TaskletExit + +class GWrap(_continuation.continulet): + """This is just a wrapper around continulet to allow + to stick additional attributes to a continulet. + To be more concrete, we need a backreference to + the coroutine object""" + + +class coroutine(object): + "we can't have continulet as a base, because continulets can't be rebound" + + def __init__(self): + self._frame = None + self.is_zombie = False + + def __getattr__(self, attr): + return getattr(self._frame, attr) + + def __del__(self): + self.is_zombie = True + del self._frame + self._frame = None + + def bind(self, func, *argl, **argd): + """coro.bind(f, *argl, **argd) -> None. + binds function f to coro. f will be called with + arguments *argl, **argd + """ + if self._frame is None or not self._frame.is_pending(): + + def _func(c, *args, **kwargs): + return func(*args, **kwargs) + + run = partial(_func, *argl, **argd) + self._frame = frame = GWrap(run) + else: + raise ValueError("cannot bind a bound coroutine") + + def switch(self): + """coro.switch() -> returnvalue + switches to coroutine coro. If the bound function + f finishes, the returnvalue is that of f, otherwise + None is returned + """ + current = _getcurrent() + current._jump_to(self) + + def _jump_to(self, coroutine): + _tls.current_coroutine = coroutine + self._frame.switch(to=coroutine._frame) + + def kill(self): + """coro.kill() : kill coroutine coro""" + _tls.current_coroutine = self + self._frame.throw(CoroutineExit) + + def _is_alive(self): + if self._frame is None: + return False + return not self._frame.is_pending() + is_alive = property(_is_alive) + del _is_alive + + def getcurrent(): + """coroutine.getcurrent() -> the currently running coroutine""" + try: + return _getcurrent() + except AttributeError: + return _maincoro + getcurrent = staticmethod(getcurrent) + + def __reduce__(self): + raise TypeError, 'pickling is not possible based upon continulets' + + +def _getcurrent(): + "Returns the current coroutine (i.e. the one which called this function)." + try: + return _tls.current_coroutine + except AttributeError: + # first call in this thread: current == main + _coroutine_create_main() + return _tls.current_coroutine + try: - # If _stackless can be imported then TaskletExit and CoroutineExit are - # automatically added to the builtins. - from _stackless import coroutine, greenlet -except ImportError: # we are running from CPython - from greenlet import greenlet, GreenletExit - TaskletExit = CoroutineExit = GreenletExit - del GreenletExit - try: - from functools import partial - except ImportError: # we are not running python 2.5 - class partial(object): - # just enough of 'partial' to be usefull - def __init__(self, func, *argl, **argd): - self.func = func - self.argl = argl - self.argd = argd + from thread import _local +except ImportError: + class _local(object): # assume no threads + pass - def __call__(self): - return self.func(*self.argl, **self.argd) +_tls = _local() - class GWrap(greenlet): - """This is just a wrapper around greenlets to allow - to stick additional attributes to a greenlet. - To be more concrete, we need a backreference to - the coroutine object""" +def _coroutine_create_main(): + # create the main coroutine for this thread + _tls.current_coroutine = None + main_coroutine = coroutine() + main_coroutine.bind(lambda x:x) + _tls.main_coroutine = main_coroutine + _tls.current_coroutine = main_coroutine + return main_coroutine - class MWrap(object): - def __init__(self,something): - self.something = something - def __getattr__(self, attr): - return getattr(self.something, attr) +_maincoro = _coroutine_create_main() - class coroutine(object): - "we can't have greenlet as a base, because greenlets can't be rebound" - - def __init__(self): - self._frame = None - self.is_zombie = False - - def __getattr__(self, attr): - return getattr(self._frame, attr) - - def __del__(self): - self.is_zombie = True - del self._frame - self._frame = None - - def bind(self, func, *argl, **argd): - """coro.bind(f, *argl, **argd) -> None. - binds function f to coro. f will be called with - arguments *argl, **argd - """ - if self._frame is None or self._frame.dead: - self._frame = frame = GWrap() - frame.coro = self - if hasattr(self._frame, 'run') and self._frame.run: - raise ValueError("cannot bind a bound coroutine") - self._frame.run = partial(func, *argl, **argd) - - def switch(self): - """coro.switch() -> returnvalue - switches to coroutine coro. If the bound function - f finishes, the returnvalue is that of f, otherwise - None is returned - """ - try: - return greenlet.switch(self._frame) - except TypeError, exp: # self._frame is the main coroutine - return greenlet.switch(self._frame.something) - - def kill(self): - """coro.kill() : kill coroutine coro""" - self._frame.throw() - - def _is_alive(self): - if self._frame is None: - return False - return not self._frame.dead - is_alive = property(_is_alive) - del _is_alive - - def getcurrent(): - """coroutine.getcurrent() -> the currently running coroutine""" - try: - return greenlet.getcurrent().coro - except AttributeError: - return _maincoro - getcurrent = staticmethod(getcurrent) - - def __reduce__(self): - raise TypeError, 'pickling is not possible based upon greenlets' - - _maincoro = coroutine() - maingreenlet = greenlet.getcurrent() - _maincoro._frame = frame = MWrap(maingreenlet) - frame.coro = _maincoro - del frame - del maingreenlet from collections import deque import operator -__all__ = 'run getcurrent getmain schedule tasklet channel coroutine \ - greenlet'.split() +__all__ = 'run getcurrent getmain schedule tasklet channel coroutine'.split() _global_task_id = 0 _squeue = None @@ -131,7 +134,8 @@ def _scheduler_remove(value): try: del _squeue[operator.indexOf(_squeue, value)] - except ValueError:pass + except ValueError: + pass def _scheduler_append(value, normal=True): if normal: _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit