Author: Armin Rigo <[email protected]>
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")
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit