[pypy-commit] pypy stacklet: Tests and partial implementation.

arigo noreply at buildbot.pypy.org
Thu Aug 18 16:35:10 CEST 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: stacklet
Changeset: r46605:da8130b98df2
Date: 2011-08-18 16:11 +0200
http://bitbucket.org/pypy/pypy/changeset/da8130b98df2/

Log:	Tests and partial implementation.

diff --git a/pypy/module/_continuation/interp_continuation.py b/pypy/module/_continuation/interp_continuation.py
--- a/pypy/module/_continuation/interp_continuation.py
+++ b/pypy/module/_continuation/interp_continuation.py
@@ -47,7 +47,8 @@
             start_state.clear()
             raise getmemoryerror(self.space)
 
-    def descr_switch(self, w_value=None):
+    def descr_switch(self, w_value=None, w_to=None):
+        to = self.space.interp_w(W_Continulet, w_to, can_be_None=True)
         if self.sthread is None:
             raise geterror(self.space, "continulet not initialized yet")
         if self.sthread.is_empty_handle(self.h):
@@ -55,11 +56,27 @@
         ec = self.check_sthread()
         saved_topframeref = ec.topframeref
         start_state.w_value = w_value
+        #
+        if to is None:
+            start_state.origin = None
+            h = self.h      # simple switch: going to self.h
+        else:
+            start_state.origin = self
+            h = to.h        # double switch: the final destination is to.h
+        #
         try:
-            self.h = self.sthread.switch(self.h)
+            h = self.sthread.switch(h)
         except MemoryError:
             start_state.clear()
             raise getmemoryerror(self.space)
+        #
+        origin = start_state.origin
+        if origin is not None:
+            # double switch ('self' is now the final destination)
+            start_state.origin = None
+            h, origin.h = origin.h, h
+        self.h = h
+        #
         ec = self.sthread.ec
         ec.topframeref = saved_topframeref
         if start_state.propagate_exception:
diff --git a/pypy/module/_continuation/test/test_stacklet.py b/pypy/module/_continuation/test/test_stacklet.py
--- a/pypy/module/_continuation/test/test_stacklet.py
+++ b/pypy/module/_continuation/test/test_stacklet.py
@@ -362,24 +362,124 @@
         assert tb.tb_next.tb_next.tb_next.tb_next is None
 
     def test_switch2_simple(self):
-        skip("in-progress")
         from _continuation import continulet
         #
         def f1(c1):
-            res = c1.switch_to(c2)
+            res = c1.switch('started 1')
             assert res == 'a'
+            res = c1.switch('b', to=c2)
+            assert res == 'c'
+            return 42
+        def f2(c2):
+            res = c2.switch('started 2')
+            assert res == 'b'
+            res = c2.switch('c', to=c1)
+            not_reachable
+        #
+        c1 = continulet(f1)
+        c2 = continulet(f2)
+        res = c1.switch()
+        assert res == 'started 1'
+        res = c2.switch()
+        assert res == 'started 2'
+        res = c1.switch('a')
+        assert res == 42
+
+    def test_switch2_pingpong(self):
+        from _continuation import continulet
+        #
+        def f1(c1):
+            res = c1.switch('started 1')
+            assert res == 'go'
+            for i in range(10):
+                res = c1.switch(i, to=c2)
+                assert res == 100 + i
+            return 42
+        def f2(c2):
+            res = c2.switch('started 2')
+            for i in range(10):
+                assert res == i
+                res = c2.switch(100 + i, to=c1)
+            not_reachable
+        #
+        c1 = continulet(f1)
+        c2 = continulet(f2)
+        res = c1.switch()
+        assert res == 'started 1'
+        res = c2.switch()
+        assert res == 'started 2'
+        res = c1.switch('go')
+        assert res == 42
+
+    def test_switch2_more_complex(self):
+        from _continuation import continulet
+        #
+        def f1(c1):
+            res = c1.switch(to=c2)
+            assert res == 'a'
+            res = c1.switch('b', to=c2)
+            assert res == 'c'
             return 41
         def f2(c2):
-            c2.switch_to(c1, 'a')
+            res = c2.switch('a', to=c1)
+            assert res == 'b'
             return 42
         #
         c1 = continulet(f1)
         c2 = continulet(f2)
         res = c1.switch()
+        assert res == 42
+        assert not c2.is_pending()
+        res = c1.switch('c')
         assert res == 41
-        assert c2.is_pending()    # already
+
+    def test_switch2_no_op(self):
+        from _continuation import continulet
+        #
+        def f1(c1):
+            res = c1.switch('a', to=c1)
+            assert res == 'a'
+            return 42
+        #
+        c1 = continulet(f1)
+        res = c1.switch()
+        assert res == 42
+
+    def test_switch2_immediately_away(self):
+        from _continuation import continulet
+        #
+        def f1(c1):
+            return 'm'
+        #
+        def f2(c2):
+            res = c2.switch('z')
+            assert res == 'a'
+            return None
+        #
+        c1 = continulet(f1)
+        c2 = continulet(f2)
         res = c2.switch()
-        assert res == 42
+        assert res == 'z'
+        res = c1.switch('a', to=c2)
+        assert res == 'm'
+
+    def test_switch2_immediately_away_corner_case(self):
+        from _continuation import continulet
+        #
+        def f1(c1):
+            this_is_never_seen
+        #
+        def f2(c2):
+            res = c2.switch('z')
+            assert res is None
+            return 'b'    # this goes back into the caller, which is f1,
+                          # but f1 didn't start yet, so a None-value value
+                          # has nowhere to go to...
+        c1 = continulet(f1)
+        c2 = continulet(f2)
+        res = c2.switch()
+        assert res == 'z'
+        raises(TypeError, c1.switch, to=c2)  # "can't send non-None value"
 
     def test_various_depths(self):
         skip("may fail on top of CPython")


More information about the pypy-commit mailing list