[pypy-svn] r28549 - in pypy/dist/pypy/module/stackless: . test

cfbolz at codespeak.net cfbolz at codespeak.net
Thu Jun 8 18:30:04 CEST 2006


Author: cfbolz
Date: Thu Jun  8 18:30:03 2006
New Revision: 28549

Modified:
   pypy/dist/pypy/module/stackless/interp_coroutine.py
   pypy/dist/pypy/module/stackless/test/test_interp_coroutine.py
Log:
(tismer, cfbolz): work in progress: make Coroutines run on top py.py, maybe.
there's a bug right now :-(


Modified: pypy/dist/pypy/module/stackless/interp_coroutine.py
==============================================================================
--- pypy/dist/pypy/module/stackless/interp_coroutine.py	(original)
+++ pypy/dist/pypy/module/stackless/interp_coroutine.py	Thu Jun  8 18:30:03 2006
@@ -31,6 +31,28 @@
 
 from pypy.interpreter.baseobjspace import Wrappable
 from pypy.rpython.rstack import yield_current_frame_to_caller, resume_point
+from pypy.rpython.objectmodel import we_are_translated
+
+try:
+    from py.magic import greenlet
+    main_greenlet = greenlet.getcurrent()
+    class MyGreenlet(object):
+        def __init__(self, thunk=None, curr=False):
+            if curr:
+                self.greenlet = greenlet.getcurrent()
+            else:
+                self.greenlet = greenlet(thunk)
+        def switch(self):
+            last = MyGreenlet(curr=True)
+# XXX unclear what to do there
+#            self.greenlet.parent = greenlet.getcurrent()
+            return self.greenlet.switch(last)
+    GreenletExit = greenlet.GreenletExit
+except ImportError:
+    def greenlet(*args, **kwargs):
+        raise NotImplementedError("need either greenlets or a translated version of pypy")
+    class GreenletExit(Exception):
+        pass
 
 import sys, os
 
@@ -56,57 +78,75 @@
     check_for_zombie = staticmethod(check_for_zombie)
 
     def postpone_deletion(obj):
-        costate.to_delete.append(obj)
-        costate.things_to_do = True
+        main_coroutine_getter._get_default_costate().to_delete.append(obj)
+        main_coroutine_getter._get_default_costate().things_to_do = True
     postpone_deletion = staticmethod(postpone_deletion)
 
     def do_things_to_do():
         # inlineable stub
-        if costate.things_to_do:
-            costate._do_things_to_do()
+        if main_coroutine_getter._get_default_costate().things_to_do:
+            main_coroutine_getter._get_default_costate()._do_things_to_do()
     do_things_to_do = staticmethod(do_things_to_do)
 
     def _do_things_to_do():
-        if costate.temp_exc is not None:
+        main_costate = main_coroutine_getter._get_default_costate()
+        if main_costate.temp_exc is not None:
             # somebody left an unhandled exception and switched to us.
             # this both provides default exception handling and the
             # way to inject an exception, like CoroutineExit.
-            e, costate.temp_exc = costate.temp_exc, None
-            costate.things_to_do = len(costate.to_delete)
+            e, main_costate.temp_exc = main_costate.temp_exc, None
+            main_costate.things_to_do = len(main_costate.to_delete)
             raise e
-        while costate.to_delete:
-            delete, costate.to_delete = costate.to_delete, []
+        while main_costate.to_delete:
+            delete, main_costate.to_delete = main_costate.to_delete, []
             for obj in delete:
                 obj.parent = obj.costate.current
                 obj._kill_finally()
         else:
-            costate.things_to_do = False
+            main_costate.things_to_do = False
     _do_things_to_do = staticmethod(_do_things_to_do)
 
 
 class CoroutineDamage(SystemError):
     pass
 
+class MainCoroutineGetter(object):
+    def __init__(self):
+        self.costate = None
+    def _get_default_costate(self):
+        if self.costate is None:
+            costate = CoState()
+            self.costate = costate
+            return costate
+        return self.costate
+            
+main_coroutine_getter = MainCoroutineGetter()
+
 class CoroutineExit(SystemExit):
     # XXX SystemExit's __init__ creates problems in bookkeeper.
     def __init__(self):
         pass
 
+def get_exit_class():  # XXX hum
+    if we_are_translated():
+        return CoroutineExit
+    else:
+        return GreenletExit
+
 class AbstractThunk(object):
     def call(self):
         raise NotImplementedError("abstract base class")
 
 class Coroutine(Wrappable):
-
     def __init__(self, state=None):
         self.frame = None
         if state is None:
-            state = costate
+            state = main_coroutine_getter._get_default_costate()
         self.costate = state
         self.parent = None
 
     def _get_default_parent(self):
-        return self.costate.current
+        return main_coroutine_getter._get_default_costate().current
 
     def bind(self, thunk):
         assert isinstance(thunk, AbstractThunk)
@@ -114,20 +154,38 @@
             raise CoroutineDamage
         if self.parent is None:
             self.parent = self._get_default_parent()
-        self.frame = self._bind(thunk)
+        assert self.parent is not None
+        if we_are_translated():
+            self.frame = self._bind(thunk)
+        else:
+            self.frame = self._greenlet_bind(thunk)
+
+    def _greenlet_bind(self, thunk):
+        state = self.costate
+        self.parent = state.current
+        assert self.parent is not None
+        def _greenlet_execute(incoming_frame):
+            return self._execute(thunk, state, incoming_frame)
+        return MyGreenlet(_greenlet_execute)
 
     def _bind(self, thunk):
         state = self.costate
         self.parent = state.current
         incoming_frame = yield_current_frame_to_caller()
+        return self._execute(thunk, state, incoming_frame)
+
+    def _execute(self, thunk, state, incoming_frame):
         left = state.last
         left.frame = incoming_frame
         left.goodbye()
         self.hello()
         try:
-            costate.do_things_to_do()
+            main_coroutine_getter._get_default_costate().do_things_to_do()
             thunk.call()
             resume_point("coroutine__bind", self, state)
+        except GreenletExit:
+            # ignore a shutdown exception
+            pass
         except CoroutineExit:
             # ignore a shutdown exception
             pass
@@ -152,13 +210,13 @@
         left.frame = incoming_frame
         left.goodbye()
         self.hello()
-        costate.do_things_to_do()
+        main_coroutine_getter._get_default_costate().do_things_to_do()
 
     def kill(self):
         if self.frame is None:
             return
-        costate.things_to_do = True
-        costate.temp_exc = CoroutineExit()
+        main_coroutine_getter._get_default_costate().things_to_do = True
+        main_coroutine_getter._get_default_costate().temp_exc = get_exit_class()()
         state = self.costate
         self.parent = state.current
         self.switch()
@@ -170,7 +228,7 @@
             pass # maybe print a warning?
         self.kill()
 
-    def __del__(self):
+    def X__del__(self):
         # provide the necessary clean-up if this coro is left
         # with a frame.
         # note that AppCoroutine has to take care about this
@@ -179,7 +237,7 @@
         # not in the position to issue a switch.
         # we defer it completely.
         if self.frame is not None:
-            costate.postpone_deletion(self)
+            main_coroutine_getter._get_default_costate().postpone_deletion(self)
 
     def _userdel(self):
         # override this for exposed coros
@@ -189,19 +247,20 @@
         return self.frame is not None or self is self.costate.current
 
     def is_zombie(self):
-        return self.frame is not None and costate.check_for_zombie(self)
+        return self.frame is not None and main_coroutine_getter._get_default_costate().check_for_zombie(self)
 
     def getcurrent():
-        return costate.current
+        return main_coroutine_getter._get_default_costate().current
     getcurrent = staticmethod(getcurrent)
 
+    def getmain():
+        return main_coroutine_getter._get_default_costate().main
+    getmain = staticmethod(getmain)
+
     def hello(self):
         "Called when execution is transferred into this coroutine."
 
     def goodbye(self):
         "Called just after execution is transferred away from this coroutine."
 
-costate = None
-costate = CoState()
-
 # _________________________________________________

Modified: pypy/dist/pypy/module/stackless/test/test_interp_coroutine.py
==============================================================================
--- pypy/dist/pypy/module/stackless/test/test_interp_coroutine.py	(original)
+++ pypy/dist/pypy/module/stackless/test/test_interp_coroutine.py	Thu Jun  8 18:30:03 2006
@@ -3,22 +3,22 @@
 """
 
 import os
-from pypy.module.stackless.interp_coroutine import costate, Coroutine, AbstractThunk
+from pypy.module.stackless.interp_coroutine import main_coroutine_getter, Coroutine, AbstractThunk
 from pypy.translator.c.test.test_stackless import StacklessTest
 from pypy.translator.c import gc
 
 def output(stuff):
     os.write(2, stuff + '\n')
 
-
 class TestCoroutine(StacklessTest):
     backendopt = True
     stacklessmode = True
     gcpolicy = gc.BoehmGcPolicy
     Coroutine = Coroutine
 
-    def setup_meth(self):
-        costate.__init__()
+    def setup_method(self, method):
+        main_coroutine_getter.costate = None
+        main_coroutine_getter.costate = None
 
     def _freeze_(self):    # for 'self.Coroutine'
         return True
@@ -51,7 +51,7 @@
 
         def f():
             lst = [1]
-            coro_f = costate.main
+            coro_f = Coroutine.getcurrent()
             coro_g = self.Coroutine()
             coro_h = self.Coroutine()
             coros = [coro_f, coro_g, coro_h]
@@ -146,7 +146,7 @@
             return n     
 
         def f():
-            coro_f = costate.main
+            coro_f = Coroutine.getcurrent()
             coro_f1 = self.Coroutine()
             thunk_f1 = T1(f1, coro_f1)
             output('binding f1 after f set 1')
@@ -159,6 +159,7 @@
         assert data == 12345678
 
     def test_kill_raise_del_coro(self):
+        py.test.skip("does not work :-(")
         class T(AbstractThunk):
             def __init__(self, func, arg):
                 self.func = func
@@ -172,9 +173,10 @@
                 raise ValueError
             if nrec:
                 g(nrec-1, t, count+1)
-            costate.main.switch()
+            Coroutine.getmain().switch()
 
         def f():
+            assert Coroutine.getmain().frame is None
             coro_g = self.Coroutine()
             thunk_g = T(g, 42)
             coro_g.bind(thunk_g)
@@ -246,7 +248,7 @@
 
             def call(self):
                 self.result = self.consume(self.tree)
-                costate.main.switch()
+                Coroutine.getmain().switch()
 
         def pre_order_eq(t1, t2):
             objects = []
@@ -270,3 +272,8 @@
 
         output = self.wrap_stackless_function(ep)
         assert output == int('0110')
+
+class TestCoroutineOnCPython(TestCoroutine):
+    def wrap_stackless_function(self, func):
+        return func()
+



More information about the Pypy-commit mailing list