[pypy-svn] r34932 - in pypy/dist/pypy/module/_stackless: . test

arigo at codespeak.net arigo at codespeak.net
Fri Nov 24 14:00:41 CET 2006


Author: arigo
Date: Fri Nov 24 14:00:39 2006
New Revision: 34932

Modified:
   pypy/dist/pypy/module/_stackless/coroutine.py
   pypy/dist/pypy/module/_stackless/interp_coroutine.py
   pypy/dist/pypy/module/_stackless/test/test_clonable.py
Log:
(pedronis, arigo)

Test and bug fix for an obscure problem in _execute(), where the local
'self' is not correct if the coroutine is a clone -- it still points to
the original.  Reload it from costate.current instead.

Sidenotedly, 'ddd' is slightly less pain than 'gdb' to debug compiled
pypy-c's.


Modified: pypy/dist/pypy/module/_stackless/coroutine.py
==============================================================================
--- pypy/dist/pypy/module/_stackless/coroutine.py	(original)
+++ pypy/dist/pypy/module/_stackless/coroutine.py	Fri Nov 24 14:00:39 2006
@@ -86,9 +86,9 @@
         if self.frame is None:
             raise OperationError(space.w_ValueError, space.wrap(
                 "cannot switch to an unbound Coroutine"))
-        self.switch()
-        rstack.resume_point("w_switch", self, space)
         state = self.costate
+        self.switch()
+        rstack.resume_point("w_switch", state, space)
         w_ret, state.w_tempval = state.w_tempval, space.w_None
         return w_ret
 
@@ -202,8 +202,8 @@
         costate = self.costate
         # now the big fun of recreating tiny things...
         bottom = resume_state_create(None, "yield_current_frame_to_caller_1")
-        # resume_point("coroutine__bind", self, state)
-        _bind_frame = resume_state_create(bottom, "coroutine__bind", self, costate)
+        # resume_point("coroutine__bind", state)
+        _bind_frame = resume_state_create(bottom, "coroutine__bind", costate)
         # rstack.resume_point("appthunk", costate, returns=w_result)
         appthunk_frame = resume_state_create(_bind_frame, "appthunk", costate)
         chain = appthunk_frame
@@ -231,10 +231,10 @@
                 call_frame = resume_state_create(dispatch_call_frame, 'call_function', frame)
             chain = call_frame
 
-        # rstack.resume_point("w_switch", self, space)
-        w_switch_frame = resume_state_create(chain, 'w_switch', self, space)
-        # resume_point("coroutine_switch", self, state, returns=incoming_frame)
-        switch_frame = resume_state_create(w_switch_frame, "coroutine_switch", self, costate)
+        # rstack.resume_point("w_switch", state, space)
+        w_switch_frame = resume_state_create(chain, 'w_switch', costate, space)
+        # resume_point("coroutine_switch", state, returns=incoming_frame)
+        switch_frame = resume_state_create(w_switch_frame, "coroutine_switch", costate)
         self.frame = switch_frame
 
 # _mixin_ did not work

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	Fri Nov 24 14:00:39 2006
@@ -217,11 +217,15 @@
                     thunk = self.thunk
                     self.thunk = None
                     thunk.call()
-                    resume_point("coroutine__bind", self, state)
+                    resume_point("coroutine__bind", state)
                 except Exception, e:
                     exc = e
                     raise
             finally:
+                # warning! we must reload the 'self' from the costate,
+                # because after a clone() the 'self' of both copies
+                # point to the original!
+                self = state.current
                 self.finish(exc)
         except CoroutineExit:
             # ignore a shutdown exception
@@ -242,7 +246,7 @@
             raise CoroutineDamage
         state = self.costate
         incoming_frame = state.update(self).switch()
-        resume_point("coroutine_switch", self, state, returns=incoming_frame)
+        resume_point("coroutine_switch", state, returns=incoming_frame)
         syncstate.switched(incoming_frame)
 
     def kill(self):

Modified: pypy/dist/pypy/module/_stackless/test/test_clonable.py
==============================================================================
--- pypy/dist/pypy/module/_stackless/test/test_clonable.py	(original)
+++ pypy/dist/pypy/module/_stackless/test/test_clonable.py	Fri Nov 24 14:00:39 2006
@@ -17,67 +17,96 @@
 
 
     def test_solver(self):
-        import new, sys
+        import _stackless
 
-        mod = new.module('mod')
-        sys.modules['mod'] = mod
-        try:
-            exec '''
-import _stackless
-
-class Fail(Exception):
-    pass
-
-class Success(Exception):
-    pass
-
-def first_solution(func):
-    global next_answer
-    co = _stackless.clonable()
-    co.bind(func)
-    pending = [(co, None)]
-    while pending:
-        co, next_answer = pending.pop()
-        try:
-            co.switch()
-        except Fail:
+        class Fail(Exception):
             pass
-        except Success, e:
-            return e.args[0]
-        else:
-            # zero_or_one() called, clone the coroutine
-            co2 = co.clone()
-            pending.append((co2, 1))
-            pending.append((co, 0))
-    raise Fail("no solution")
-
-pending = []
-main = _stackless.clonable.getcurrent()
-
-def zero_or_one():
-    main.switch()
-    return next_answer
-
-# ____________________________________________________________
-
-invalid_prefixes = {
-    (0, 0): True,
-    (0, 1, 0): True,
-    (0, 1, 1): True,
-    (1, 0): True,
-    (1, 1, 0, 0): True,
-    }
-
-def example():
-    test = []
-    for n in range(5):
-        test.append(zero_or_one())
-        if tuple(test) in invalid_prefixes:
-            raise Fail
-    raise Success(test)
-
-res = first_solution(example)
-assert res == [1, 1, 0, 1, 0]
-''' in mod.__dict__
-        finally:
-            del sys.modules['mod']
+
+        class Success(Exception):
+            pass
+
+        def first_solution(func):
+            global next_answer
+            co = _stackless.clonable()
+            co.bind(func)
+            pending = [(co, None)]
+            while pending:
+                co, next_answer = pending.pop()
+                try:
+                    co.switch()
+                except Fail:
+                    pass
+                except Success, e:
+                    return e.args[0]
+                else:
+                    # zero_or_one() called, clone the coroutine
+                    co2 = co.clone()
+                    pending.append((co2, 1))
+                    pending.append((co, 0))
+            raise Fail("no solution")
+
+        pending = []
+        main = _stackless.clonable.getcurrent()
+
+        def zero_or_one():
+            main.switch()
+            return next_answer
+
+        # ____________________________________________________________
+
+        invalid_prefixes = {
+            (0, 0): True,
+            (0, 1, 0): True,
+            (0, 1, 1): True,
+            (1, 0): True,
+            (1, 1, 0, 0): True,
+            }
+
+        def example():
+            test = []
+            for n in range(5):
+                test.append(zero_or_one())
+                if tuple(test) in invalid_prefixes:
+                    raise Fail
+            raise Success(test)
+
+        res = first_solution(example)
+        assert res == [1, 1, 0, 1, 0]
+
+
+    def test_myself_may_not_be_me_any_more(self):
+        import gc
+        from _stackless import clonable
+
+        counter = [0]
+
+        def runner():
+            while 1:
+                assert clonable.getcurrent() is coro
+                counter[0] += 1
+                main.switch()
+
+        main = clonable.getcurrent()
+        coro = clonable()
+        coro.bind(runner)
+
+        coro.switch()
+        assert counter == [1]
+
+        assert clonable.getcurrent() is main
+        coro1 = coro.clone()
+        assert counter == [1]
+        assert clonable.getcurrent() is main
+        coro.switch()
+        assert counter == [2]
+        coro.switch()
+        assert counter == [3]
+        assert clonable.getcurrent() is main
+        del coro1
+        gc.collect()
+        #print "collected!"
+        assert clonable.getcurrent() is main
+        assert counter == [3]
+        coro.switch()
+        assert clonable.getcurrent() is main
+        assert counter == [4]



More information about the Pypy-commit mailing list