[pypy-svn] r28747 - in pypy/dist/pypy: lib module/_stackless module/_stackless/test
cfbolz at codespeak.net
cfbolz at codespeak.net
Tue Jun 13 16:47:58 CEST 2006
Author: cfbolz
Date: Tue Jun 13 16:47:57 2006
New Revision: 28747
Added:
pypy/dist/pypy/module/_stackless/interp_greenlet.py
pypy/dist/pypy/module/_stackless/test/test_greenlet.py
Modified:
pypy/dist/pypy/lib/stackless.py
pypy/dist/pypy/module/_stackless/__init__.py
Log:
first go at implementing greenlets. works mostly, some things (like GreenletExit) are missing)
Modified: pypy/dist/pypy/lib/stackless.py
==============================================================================
--- pypy/dist/pypy/lib/stackless.py (original)
+++ pypy/dist/pypy/lib/stackless.py Tue Jun 13 16:47:57 2006
@@ -25,9 +25,9 @@
print task
raise
-from _stackless import coroutine
+from _stackless import coroutine, greenlet
-__all__ = 'run getcurrent getmain schedule tasklet channel TaskletExit coroutine'.split()
+__all__ = 'run getcurrent getmain schedule tasklet channel TaskletExit coroutine greenlet'.split()
class TaskletExit(Exception):pass
Modified: pypy/dist/pypy/module/_stackless/__init__.py
==============================================================================
--- pypy/dist/pypy/module/_stackless/__init__.py (original)
+++ pypy/dist/pypy/module/_stackless/__init__.py Tue Jun 13 16:47:57 2006
@@ -12,10 +12,14 @@
interpleveldefs = {
'tasklet' : 'interp_stackless.tasklet',
'coroutine' : 'coroutine.AppCoroutine',
+ 'greenlet' : 'interp_greenlet.AppGreenlet',
}
def setup_after_space_initialization(self):
# post-installing classmethods/staticmethods which
# are not yet directly supported
- from pypy.module._stackless.coroutine import post_install
- post_install(self)
+ from pypy.module._stackless.coroutine import post_install as post_install_coro
+ post_install_coro(self)
+ from pypy.module._stackless.interp_greenlet import post_install as post_install_greenlet
+ post_install_greenlet(self)
+
Added: pypy/dist/pypy/module/_stackless/interp_greenlet.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/module/_stackless/interp_greenlet.py Tue Jun 13 16:47:57 2006
@@ -0,0 +1,167 @@
+from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.argument import Arguments
+from pypy.interpreter.typedef import GetSetProperty, TypeDef
+from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w
+from pypy.interpreter.gateway import interp2app, ObjSpace, W_Root
+from pypy.interpreter.error import OperationError
+from pypy.interpreter.function import StaticMethod
+
+from pypy.module._stackless.stackless_flags import StacklessFlags
+from pypy.module._stackless.interp_coroutine import Coroutine, BaseCoState, AbstractThunk
+from pypy.module._stackless.coroutine import _AppThunk, makeStaticMethod
+
+class GreenletThunk(AbstractThunk):
+
+ def __init__(self, space, costate, greenlet):
+ self.space = space
+ self.costate = costate
+ self.greenlet = greenlet
+
+ def call(self):
+ __args__ = self.costate.__args__
+ assert __args__ is not None
+ try:
+ try:
+ w_result = self.space.call_args(self.greenlet.w_callable, __args__)
+ except OperationError, operr:
+ self.greenlet.w_dead = self.space.w_True
+ self.costate.operr = operr
+ w_result = self.space.w_None
+ else:
+ self.greenlet.w_dead = self.space.w_True
+ while 1:
+ __args__ = Arguments(self.space, [w_result])
+ try:
+ w_result = self.greenlet.w_parent.w_switch(__args__)
+ except OperationError, operr:
+ self.costate.operr = operr
+ except Exception, e:
+ print "bad idea", e
+
+class AppGreenletCoState(BaseCoState):
+ def __init__(self, space):
+ BaseCoState.__init__(self)
+ self.__args__ = None
+ self.space = space
+ self.operr = None
+
+ def post_install(self):
+ self.current = self.main = self.last = AppGreenlet(self.space, is_main=True)
+
+class GreenletExit(Exception):
+ pass
+
+class AppGreenlet(Coroutine):
+ def __init__(self, space, w_callable=None, is_main=False):
+ self.space = space
+ self.w_callable = w_callable
+ self.w_dead = space.w_False
+ self.has_ever_run = False or is_main
+ self.is_main = is_main
+ state = self._get_state(space)
+ if is_main:
+ self.w_parent = space.w_None
+ else:
+ self.w_parent = state.current
+ Coroutine.__init__(self, state)
+ if not is_main:
+ space.getexecutioncontext().subcontext_new(self)
+ self.bind(GreenletThunk(space, state, self))
+
+ def descr_method__new__(space, w_subtype, w_callable):
+ co = space.allocate_instance(AppGreenlet, w_subtype)
+ AppGreenlet.__init__(co, space, w_callable)
+ return space.wrap(co)
+
+ def _get_state(space):
+ return space.fromcache(AppGreenletCoState)
+ _get_state = staticmethod(_get_state)
+
+ def hello(self):
+ ec = self.space.getexecutioncontext()
+ ec.subcontext_enter(self)
+
+ def goodbye(self):
+ ec = self.space.getexecutioncontext()
+ ec.subcontext_leave(self)
+
+ def w_getcurrent(space):
+ return space.wrap(AppGreenlet._get_state(space).current)
+ w_getcurrent = staticmethod(w_getcurrent)
+
+ def w_switch(self, __args__):
+ #print "switch", __args__, id(self)
+ if __args__.num_kwds():
+ raise OperationError(
+ space.w_TypeError,
+ space.wrap("switch() takes not keyword arguments"))
+ self.has_ever_run = True
+ self.costate.__args__ = __args__
+ self.switch()
+ #print "after switch"
+ #print self.costate.__args__
+ if self.costate.operr is not None:
+ operr = self.costate.operr
+ self.costate.operr = None
+ raise operr
+ args_w, kwds_w = self.costate.__args__.unpack()
+ if args_w is None:
+ return self.space.w_None
+ if len(args_w) == 1:
+ return args_w[0]
+ return self.space.newtuple(args_w)
+
+ def w_throw(self, w_exception):
+ self.costate.operr = OperationError(w_exception, self.space.wrap(""))
+ self.w_switch(Arguments([]))
+
+ def _userdel(self):
+ self.space.userdel(self)
+
+def w_get_is_dead(space, self):
+ return self.w_dead
+
+def descr__bool__(space, w_self):
+ return space.wrap(w_self.has_ever_run and not space.is_true(w_self.w_dead))
+
+def w_get_parent(space, self):
+ return self.w_parent
+
+def w_set_parent(space, self, newparent):
+ curr = newparent
+ while 1:
+ if space.is_true(space.is_(self, curr)):
+ raise OperationError(space.w_ValueError, space.wrap("cyclic parent chain"))
+ if not space.is_true(space.is_(curr.w_parent, space.w_None)):
+ break
+ curr = curr.w_parent
+ self.w_parent = newparent
+
+def w_get_frame(space, self):
+ if not self.has_ever_run or space.is_true(self.w_dead):
+ return space.w_None
+ try:
+ return self.framestack.top(0)
+ except IndexError:
+ return space.w_None
+
+def post_install(module):
+ makeStaticMethod(module, 'greenlet', 'getcurrent')
+ space = module.space
+ AppGreenlet._get_state(space).post_install()
+
+AppGreenlet.typedef = TypeDef("greenlet",
+ __new__ = interp2app(AppGreenlet.descr_method__new__.im_func),
+ switch = interp2app(AppGreenlet.w_switch,
+ unwrap_spec=['self', Arguments]),
+ dead = GetSetProperty(w_get_is_dead),
+ parent = GetSetProperty(w_get_parent, w_set_parent),
+ getcurrent = interp2app(AppGreenlet.w_getcurrent),
+ throw = interp2app(AppGreenlet.w_throw),
+ gr_frame = GetSetProperty(w_get_frame),
+ __nonzero__ = interp2app(descr__bool__),
+# GreenletExit = GreenletExit,
+# error = GreenletExit,
+ __module__ = '_stackless',
+)
+
Added: pypy/dist/pypy/module/_stackless/test/test_greenlet.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/module/_stackless/test/test_greenlet.py Tue Jun 13 16:47:57 2006
@@ -0,0 +1,144 @@
+from pypy.conftest import gettestobjspace
+
+class AppTest_Coroutine:
+
+ def setup_class(cls):
+ space = gettestobjspace(usemodules=('_stackless',))
+ cls.space = space
+
+ def test_very_simple(self):
+ from _stackless import greenlet
+ lst = []
+ def f(x):
+ lst.append(x)
+ return x + 10
+ g = greenlet(f)
+ assert not g
+ res = g.switch(20)
+ assert res == 30
+ assert lst == [20]
+ assert g.dead
+ assert not g
+
+ def test_switch_back_to_main(self):
+ from _stackless import greenlet
+ lst = []
+ main = greenlet.getcurrent()
+ def f(x):
+ lst.append(x)
+ x = main.switch(x + 10)
+ return 40 + x
+ g = greenlet(f)
+ res = g.switch(20)
+ assert res == 30
+ assert lst == [20]
+ assert not g.dead
+ res = g.switch(2)
+ assert res == 42
+ assert g.dead
+
+ def test_simple(self):
+ from _stackless import greenlet
+ lst = []
+ gs = []
+ def f():
+ lst.append(1)
+ greenlet.getcurrent().parent.switch()
+ lst.append(3)
+ g = greenlet(f)
+ lst.append(0)
+ g.switch()
+ lst.append(2)
+ g.switch()
+ lst.append(4)
+ assert lst == range(5)
+
+ def test_exception_simple(self):
+ from _stackless import greenlet
+ def f():
+ raise ValueError
+ g1 = greenlet(f)
+ raises(ValueError, g1.switch)
+
+ def test_exception_propagate(self):
+ from _stackless import greenlet
+ def f():
+ raise ValueError
+ def g():
+ return g1.switch()
+ g1 = greenlet(f)
+ g2 = greenlet(g)
+ raises(ValueError, g1.switch)
+ g1 = greenlet(f)
+ raises(ValueError, g2.switch)
+
+ def test_exception(self):
+ from _stackless import greenlet
+ import sys
+ def fmain(seen):
+ try:
+ greenlet.getcurrent().parent.switch()
+ except:
+ seen.append(sys.exc_info()[0])
+ raise
+ raise ValueError
+ seen = []
+ g1 = greenlet(fmain)
+ g2 = greenlet(fmain)
+ g1.switch(seen)
+ g2.switch(seen)
+ g2.parent = g1
+ assert seen == []
+ raises(ValueError, g2.switch)
+ assert seen == [ValueError]
+ g2.switch()
+ assert seen == [ValueError]
+
+ def test_send_exception(self):
+ from _stackless import greenlet
+ import sys
+ def send_exception(g, exc):
+ # note: send_exception(g, exc) can be now done with g.throw(exc).
+ # the purpose of this test is to explicitely check the propagation rules.
+ def crasher(exc):
+ raise exc
+ g1 = greenlet(crasher)
+ g1.parent = g
+ g1.switch(exc)
+ def fmain(seen):
+ try:
+ greenlet.getcurrent().parent.switch()
+ except:
+ seen.append(sys.exc_info()[0])
+ raise
+ raise ValueError
+
+ seen = []
+ g1 = greenlet(fmain)
+ g1.switch(seen)
+ raises(KeyError, "send_exception(g1, KeyError)")
+ assert seen == [KeyError]
+ seen = []
+ g1 = greenlet(fmain)
+ g1.switch(seen)
+ raises(KeyError, "g1.throw(KeyError)")
+ assert seen == [KeyError]
+ assert g1.dead
+
+ def test_frame(self):
+ from _stackless import greenlet
+ import sys
+ def f1():
+ f = sys._getframe(0)
+ assert f.f_back is None
+ greenlet.getcurrent().parent.switch(f)
+ return "meaning of life"
+ g = greenlet(f1)
+ frame = g.switch()
+ assert frame is g.gr_frame
+ assert g
+ next = g.switch()
+ assert not g
+ assert next == "meaning of life"
+ assert g.gr_frame is None
+
More information about the Pypy-commit
mailing list