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

arigo at codespeak.net arigo at codespeak.net
Tue Nov 7 13:16:33 CET 2006


Author: arigo
Date: Tue Nov  7 13:16:31 2006
New Revision: 34315

Modified:
   pypy/dist/pypy/module/_stackless/coroutine.py
   pypy/dist/pypy/module/_stackless/interp_coroutine.py
   pypy/dist/pypy/module/_stackless/test/test_coroutine.py
Log:
Fixes to coroutine pickling (relevant for bound but not running coroutines).


Modified: pypy/dist/pypy/module/_stackless/coroutine.py
==============================================================================
--- pypy/dist/pypy/module/_stackless/coroutine.py	(original)
+++ pypy/dist/pypy/module/_stackless/coroutine.py	Tue Nov  7 13:16:31 2006
@@ -15,7 +15,7 @@
 experience to decide where to set the limits.
 """
 
-from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.baseobjspace import Wrappable, UnpackValueError
 from pypy.interpreter.argument import Arguments
 from pypy.interpreter.typedef import GetSetProperty, TypeDef
 from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w
@@ -132,41 +132,62 @@
         # this is trying to be simplistic at the moment.
         # we neither allow to pickle main (which can become a mess
         # since it has some deep anchestor frames)
-        # nor we allowto pickle the current coroutine.
+        # nor we allow to pickle the current coroutine.
         # rule: switch before pickling.
         # you cannot construct the tree that you are climbing.
-        # XXX missing checks!
         from pypy.interpreter.mixedmodule import MixedModule
         w_mod    = space.getbuiltinmodule('_stackless')
         mod      = space.interp_w(MixedModule, w_mod)
         w_mod2    = space.getbuiltinmodule('_pickle_support')
         mod2      = space.interp_w(MixedModule, w_mod2)
-        new_inst = mod.get('coroutine')
+        w_new_inst = mod.get('coroutine')
         w        = space.wrap
         nt = space.newtuple
         ec = self.space.getexecutioncontext()
 
         if self is self._get_state(space).main:
-            return space.newtuple([mod2.get('return_main'), space.newtuple([])])
+            return nt([mod2.get('return_main'), nt([])])
+
+        thunk = self.thunk
+        if isinstance(thunk, _AppThunk):
+            w_args, w_kwds = thunk.args.topacked()
+            w_thunk = nt([thunk.w_func, w_args, w_kwds])
+        else:
+            w_thunk = space.w_None
 
         tup_base = [
             ]
         tup_state = [
             w(self.flags),
             ec.subcontext_getstate(self),
+            w_thunk,
+            w(self.parent),
             ]
 
-        return nt([new_inst, nt(tup_base), nt(tup_state)])
+        return nt([w_new_inst, nt(tup_base), nt(tup_state)])
 
     def descr__setstate__(self, space, w_args):
-        args_w = space.unpackiterable(w_args)
-        w_flags, w_state = args_w
+        try:
+            w_flags, w_state, w_thunk, w_parent = space.unpackiterable(w_args,
+                                                             expected_length=4)
+        except UnpackValueError, e:
+            raise OperationError(space.w_ValueError, e.msg)
         self.flags = space.int_w(w_flags)
-        self.parent = AppCoroutine._get_state(space).current
+        self.parent = space.interp_w(AppCoroutine, w_parent, can_be_None=True)
         ec = self.space.getexecutioncontext()
         ec.subcontext_setstate(self, w_state)
         self.reconstruct_framechain()
-        
+        if space.is_w(w_thunk, space.w_None):
+            self.thunk = None
+        else:
+            try:
+                w_func, w_args, w_kwds = space.unpackiterable(w_thunk,
+                                                             expected_length=3)
+            except UnpackValueError, e:
+                raise OperationError(space.w_ValueError, e.msg)
+            args = Arguments.frompacked(space, w_args, w_kwds)
+            self.bind(_AppThunk(space, self.costate, w_func, args))
+
     def reconstruct_framechain(self):
         from pypy.interpreter.pyframe import PyFrame
         from pypy.rlib.rstack import resume_state_create

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	Tue Nov  7 13:16:31 2006
@@ -214,14 +214,15 @@
                 try:
                     exc = None
                     syncstate.switched(incoming_frame)
-                    self.thunk.call()
+                    thunk = self.thunk
+                    self.thunk = None
+                    thunk.call()
                     resume_point("coroutine__bind", self, state)
                 except Exception, e:
                     exc = e
                     raise
             finally:
                 self.finish(exc)
-                self.thunk = None
         except CoroutineExit:
             # ignore a shutdown exception
             pass

Modified: pypy/dist/pypy/module/_stackless/test/test_coroutine.py
==============================================================================
--- pypy/dist/pypy/module/_stackless/test/test_coroutine.py	(original)
+++ pypy/dist/pypy/module/_stackless/test/test_coroutine.py	Tue Nov  7 13:16:31 2006
@@ -24,30 +24,18 @@
         co2.switch()
         assert result == [42]
 
-    def test_pickle_coroutine_frame(self):
-        #skip('passes in interactive interpreter but not here :/')
-        # this requires py.magic.greenlet!
-        import pickle, sys, new
-        mod = new.module('mod')
-        try: 
-            sys.modules['mod'] = mod
-            exec '''
-import sys, _stackless as stackless
-
-def f():
-        global the_frame
-        the_frame = sys._getframe()
-        main_coro.switch()
-
-co = stackless.coroutine()
-main_coro = stackless.coroutine.getcurrent()
-co.bind(f)
-co.switch()
-''' in mod.__dict__
-            pckl = pickle.dumps(mod.the_frame)
-            #co2 = pickle.loads(pckl)
-        finally:
-            del sys.modules['mod']
+    def test_pickle_coroutine_bound(self):
+        import pickle
+        import _stackless
+        lst = [4]
+        co = _stackless.coroutine()
+        co.bind(lst.append, 2)
+        pckl = pickle.dumps((co, lst))
+
+        (co2, lst2) = pickle.loads(pckl)
+        assert lst2 == [4]
+        co2.switch()
+        assert lst2 == [4, 2]
 
     def test_raise_propagate(self):
         import _stackless as stackless
@@ -111,3 +99,11 @@
         assert co.is_alive
         co.kill()
         assert not co.is_alive
+
+    def test_bogus_bind(self):
+        import _stackless as stackless
+        co = stackless.coroutine()
+        def f():
+            pass
+        co.bind(f)
+        raises(ValueError, co.bind, f)



More information about the Pypy-commit mailing list