Author: Armin Rigo <[email protected]>
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
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit