[pypy-commit] pypy stacklet: Use _continuation.permute() at the end of _greenlet_start()

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


Author: Armin Rigo <arigo at tunes.org>
Branch: stacklet
Changeset: r46660:577ea1cac4e2
Date: 2011-08-20 09:43 +0200
http://bitbucket.org/pypy/pypy/changeset/577ea1cac4e2/

Log:	Use _continuation.permute() at the end of _greenlet_start() in order
	to put the parent's continuation in place. It is enough to
	implement parents without giving up on the model that greenlet
	objects, as continulets, are not nested.

diff --git a/lib_pypy/greenlet.py b/lib_pypy/greenlet.py
--- a/lib_pypy/greenlet.py
+++ b/lib_pypy/greenlet.py
@@ -34,9 +34,12 @@
     __main = False
     __started = False
 
-    def __init__(self, run=None):
+    def __init__(self, run=None, parent=None):
         if run is not None:
             self.run = run
+        if parent is None:
+            parent = getcurrent()
+        self.parent = parent
 
     def switch(self, *args):
         "Switch execution to this greenlet, optionally passing the values "
@@ -92,14 +95,6 @@
     def dead(self):
         return self.__started and not self
 
-    @property
-    def parent(self):
-        # Don't support nesting for now.
-        if self.__main:
-            return None
-        else:
-            return _tls.main
-
 # ____________________________________________________________
 # Internal stuff
 
@@ -116,10 +111,15 @@
     gmain = greenlet.__new__(greenlet)
     gmain._greenlet__main = True
     gmain._greenlet__started = True
+    gmain.parent = None
     _tls.main = gmain
     _tls.current = gmain
 
 def _greenlet_start(greenlet, args):
     _tls.current = greenlet
-    res = greenlet.run(*args)
+    try:
+        res = greenlet.run(*args)
+    finally:
+        if greenlet.parent is not _tls.main:
+            _continuation.permute(greenlet, greenlet.parent)
     return (res,)
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
@@ -133,3 +133,54 @@
         g2.switch()
         res = g1.switch()
         assert res == "ok"
+
+    def test_nondefault_parent(self):
+        from greenlet import greenlet
+        gmain = greenlet.getcurrent()
+        #
+        def f1():
+            g2 = greenlet(f2)
+            res = g2.switch()
+            assert res == "from 2"
+            return "from 1"
+        #
+        def f2():
+            return "from 2"
+        #
+        g1 = greenlet(f1)
+        res = g1.switch()
+        assert res == "from 1"
+
+    def test_change_parent(self):
+        from greenlet import greenlet
+        gmain = greenlet.getcurrent()
+        #
+        def f1():
+            res = g2.switch()
+            assert res == "from 2"
+            return "from 1"
+        #
+        def f2():
+            return "from 2"
+        #
+        g1 = greenlet(f1)
+        g2 = greenlet(f2)
+        g2.parent = g1
+        res = g1.switch()
+        assert res == "from 1"
+
+    def test_raises_through_parent_chain(self):
+        from greenlet import greenlet
+        gmain = greenlet.getcurrent()
+        #
+        def f1():
+            raises(IndexError, g2.switch)
+            raise ValueError
+        #
+        def f2():
+            raise IndexError
+        #
+        g1 = greenlet(f1)
+        g2 = greenlet(f2)
+        g2.parent = g1
+        raises(ValueError, g1.switch)


More information about the pypy-commit mailing list