[pypy-commit] pypy stacklet: Finish the emulation; now it should support all cases supported

arigo noreply at buildbot.pypy.org
Sat Aug 20 11:18:26 CEST 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: stacklet
Changeset: r46661:2824b0cd4078
Date: 2011-08-20 09:59 +0200
http://bitbucket.org/pypy/pypy/changeset/2824b0cd4078/

Log:	Finish the emulation; now it should support all cases supported by
	greenlet.c for CPython.

diff --git a/lib_pypy/greenlet.py b/lib_pypy/greenlet.py
--- a/lib_pypy/greenlet.py
+++ b/lib_pypy/greenlet.py
@@ -50,17 +50,20 @@
         "raise exception in greenlet, return value passed when switching back"
         return self.__switch(_continulet.throw, typ, val, tb)
 
-    def __switch(self, unbound_method, *args):
+    def __switch(target, unbound_method, *args):
         current = getcurrent()
-        target = self
-        if not target:
+        #
+        while not target:
             if not target.__started:
                 _continulet.__init__(target, _greenlet_start, *args)
                 args = ()
                 target.__started = True
-            else:
-                # already done, go to main instead... xxx later
-                raise error("greenlet execution already finished")
+                break
+            # already done, go to the parent instead
+            # (NB. infinite loop possible, but unlikely, unless you mess
+            # up the 'parent' explicitly.  Good enough, because a Ctrl-C
+            # will show that the program is caught in this loop here.)
+            target = target.parent
         #
         try:
             if current.__main:
@@ -68,6 +71,7 @@
                     # switch from main to main
                     if unbound_method == _continulet.throw:
                         raise args[0], args[1], args[2]
+                    (args,) = args
                 else:
                     # enter from main to target
                     args = unbound_method(target, *args)
@@ -95,6 +99,10 @@
     def dead(self):
         return self.__started and not self
 
+    @property
+    def gr_frame(self):
+        raise NotImplementedError("attribute 'gr_frame' of greenlet objects")
+
 # ____________________________________________________________
 # Internal stuff
 
diff --git a/pypy/module/test_lib_pypy/test_greenlet.py b/pypy/module/test_lib_pypy/test_greenlet.py
--- a/pypy/module/test_lib_pypy/test_greenlet.py
+++ b/pypy/module/test_lib_pypy/test_greenlet.py
@@ -136,7 +136,6 @@
 
     def test_nondefault_parent(self):
         from greenlet import greenlet
-        gmain = greenlet.getcurrent()
         #
         def f1():
             g2 = greenlet(f2)
@@ -153,7 +152,6 @@
 
     def test_change_parent(self):
         from greenlet import greenlet
-        gmain = greenlet.getcurrent()
         #
         def f1():
             res = g2.switch()
@@ -171,7 +169,6 @@
 
     def test_raises_through_parent_chain(self):
         from greenlet import greenlet
-        gmain = greenlet.getcurrent()
         #
         def f1():
             raises(IndexError, g2.switch)
@@ -184,3 +181,53 @@
         g2 = greenlet(f2)
         g2.parent = g1
         raises(ValueError, g1.switch)
+
+    def test_switch_to_dead_1(self):
+        from greenlet import greenlet
+        #
+        def f1():
+            return "ok"
+        #
+        g1 = greenlet(f1)
+        res = g1.switch()
+        assert res == "ok"
+        res = g1.switch("goes to gmain instead")
+        assert res == "goes to gmain instead"
+
+    def test_switch_to_dead_2(self):
+        from greenlet import greenlet
+        #
+        def f1():
+            g2 = greenlet(f2)
+            return g2.switch()
+        #
+        def f2():
+            return "ok"
+        #
+        g1 = greenlet(f1)
+        res = g1.switch()
+        assert res == "ok"
+        res = g1.switch("goes to gmain instead")
+        assert res == "goes to gmain instead"
+
+    def test_switch_to_dead_3(self):
+        from greenlet import greenlet
+        gmain = greenlet.getcurrent()
+        #
+        def f1():
+            res = g2.switch()
+            assert res == "ok"
+            res = gmain.switch("next step")
+            assert res == "goes to f1 instead"
+            return "all ok"
+        #
+        def f2():
+            return "ok"
+        #
+        g1 = greenlet(f1)
+        g2 = greenlet(f2)
+        g2.parent = g1
+        res = g1.switch()
+        assert res == "next step"
+        res = g2.switch("goes to f1 instead")
+        assert res == "all ok"


More information about the pypy-commit mailing list