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

arigo at codespeak.net arigo at codespeak.net
Wed Jun 14 16:58:24 CEST 2006


Author: arigo
Date: Wed Jun 14 16:58:23 2006
New Revision: 28771

Modified:
   pypy/dist/pypy/module/_stackless/interp_coroutine.py
   pypy/dist/pypy/module/_stackless/test/test_coroutine.py
   pypy/dist/pypy/module/_stackless/test/test_interp_coroutine.py
Log:
Moved the need-to-have-only-one-of-those kind of data
to its own global 'syncstate' instance.  This fixes a
bug with app-level coroutines eating all exceptions.


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	Wed Jun 14 16:58:23 2006
@@ -80,61 +80,50 @@
     def __init__(self):
         BaseCoState.__init__(self)
         self.last = self.current = self.main = Coroutine(self)
+
+class CoroutineDamage(SystemError):
+    pass
+
+
+class SyncState(object):
+    def __init__(self):
+        self.reset()
+
+    def reset(self):
+        self.default_costate = None
         self.things_to_do = False
         self.temp_exc = None
         self.to_delete = []
 
-    def check_for_zombie(obj):
+    def check_for_zombie(self, obj):
         return co in self.to_delete
-    check_for_zombie = staticmethod(check_for_zombie)
 
-    def postpone_deletion(obj):
-        main_costate = main_costate_getter._get_default_costate()
-        main_costate.to_delete.append(obj)
-        main_costate.things_to_do = True
-    postpone_deletion = staticmethod(postpone_deletion)
+    def postpone_deletion(self, obj):
+        self.to_delete.append(obj)
+        self.things_to_do = True
 
-    def do_things_to_do():
+    def do_things_to_do(self):
         # inlineable stub
-        main_costate = main_costate_getter._get_default_costate()
-        if main_costate.things_to_do:
-            main_costate._do_things_to_do()
-    do_things_to_do = staticmethod(do_things_to_do)
-
-    def _do_things_to_do():
-        main_costate = main_costate_getter._get_default_costate()
-        if main_costate.temp_exc is not None:
+        if self.things_to_do:
+            self._do_things_to_do()
+
+    def _do_things_to_do(self):
+        if self.temp_exc is not None:
             # somebody left an unhandled exception and switched to us.
             # this both provides default exception handling and the
             # way to inject an exception, like CoroutineExit.
-            e, main_costate.temp_exc = main_costate.temp_exc, None
-            main_costate.things_to_do = len(main_costate.to_delete)
+            e, self.temp_exc = self.temp_exc, None
+            self.things_to_do = bool(self.to_delete)
             raise e
-        while main_costate.to_delete:
-            delete, main_costate.to_delete = main_costate.to_delete, []
+        while self.to_delete:
+            delete, self.to_delete = self.to_delete, []
             for obj in delete:
                 obj.parent = obj.costate.current
                 obj._kill_finally()
         else:
-            main_costate.things_to_do = False
-    _do_things_to_do = staticmethod(_do_things_to_do)
+            self.things_to_do = False
 
-
-class CoroutineDamage(SystemError):
-    pass
-
-
-class MainCostateGetter(object):
-    def __init__(self):
-        self.costate = None
-    def _get_default_costate(self):
-        if self.costate is None:
-            costate = CoState()
-            self.costate = costate
-            return costate
-        return self.costate
-
-main_costate_getter = MainCostateGetter()
+syncstate = SyncState()
 
 
 class CoroutineExit(SystemExit):
@@ -151,7 +140,7 @@
     def __init__(self, state=None):
         self.frame = None
         if state is None:
-            state = main_costate_getter._get_default_costate()
+            state = self._get_default_costate()
         self.costate = state
         self.parent = None
         self.thunk = None
@@ -164,8 +153,15 @@
         else:
             return '<coro frame=%r %s>' % (self.frame, self.thunk is not None)
 
+    def _get_default_costate():
+        state = syncstate.default_costate
+        if state is None:
+            state = syncstate.default_costate = CoState()
+        return state
+    _get_default_costate = staticmethod(_get_default_costate)
+
     def _get_default_parent(self):
-        return main_costate_getter._get_default_costate().current
+        return self.costate.current
 
     def bind(self, thunk):
         assert isinstance(thunk, AbstractThunk)
@@ -207,7 +203,7 @@
         left.goodbye()
         self.hello()
         try:
-            main_costate_getter._get_default_costate().do_things_to_do()
+            syncstate.do_things_to_do()
             try:
                 self.thunk.call()
             finally:
@@ -219,8 +215,8 @@
             pass
         except Exception, e:
             # redirect all unhandled exceptions to the parent
-            state.things_to_do = True
-            state.temp_exc = e
+            syncstate.things_to_do = True
+            syncstate.temp_exc = e
         while self.parent is not None and self.parent.frame is None:
             # greenlet behavior is fine
             self.parent = self.parent.parent
@@ -238,14 +234,14 @@
         left.frame = incoming_frame
         left.goodbye()
         state.current.hello()
-        main_costate_getter._get_default_costate().do_things_to_do()
+        syncstate.do_things_to_do()
 
     def kill(self):
         if self.frame is None:
             return
-        main_costate_getter._get_default_costate().things_to_do = True
-        main_costate_getter._get_default_costate().temp_exc = CoroutineExit()
         state = self.costate
+        syncstate.things_to_do = True
+        syncstate.temp_exc = CoroutineExit()
         self.parent = state.current
         self.switch()
 
@@ -265,7 +261,7 @@
         # not in the position to issue a switch.
         # we defer it completely.
         if self.frame is not None:
-            main_costate_getter._get_default_costate().postpone_deletion(self)
+            syncstate.postpone_deletion(self)
 
     def _userdel(self):
         # override this for exposed coros
@@ -275,14 +271,16 @@
         return self.frame is not None or self is self.costate.current
 
     def is_zombie(self):
-        return self.frame is not None and main_costate_getter._get_default_costate().check_for_zombie(self)
+        return self.frame is not None and syncstate.check_for_zombie(self)
 
     def getcurrent():
-        return main_costate_getter._get_default_costate().current
+        costate = Coroutine._get_default_costate()
+        return costate.current
     getcurrent = staticmethod(getcurrent)
 
     def getmain():
-        return main_costate_getter._get_default_costate().main
+        costate = Coroutine._get_default_costate()
+        return costate.main
     getmain = staticmethod(getmain)
 
     def hello(self):

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	Wed Jun 14 16:58:23 2006
@@ -49,4 +49,16 @@
             #co2 = pickle.loads(pckl)
         finally:
             del sys.modules['mod']
-                
+
+    def test_raise_propagate(self):
+        import _stackless as stackless
+        co = stackless.coroutine()
+        def f():
+            return 1/0
+        co.bind(f)
+        try:
+            co.switch()
+        except ZeroDivisionError:
+            pass
+        else:
+            raise AssertionError("exception not propagated")

Modified: pypy/dist/pypy/module/_stackless/test/test_interp_coroutine.py
==============================================================================
--- pypy/dist/pypy/module/_stackless/test/test_interp_coroutine.py	(original)
+++ pypy/dist/pypy/module/_stackless/test/test_interp_coroutine.py	Wed Jun 14 16:58:23 2006
@@ -3,7 +3,7 @@
 """
 
 import os
-from pypy.module._stackless.interp_coroutine import main_costate_getter, Coroutine, AbstractThunk
+from pypy.module._stackless.interp_coroutine import syncstate, Coroutine, AbstractThunk
 from pypy.translator.c.test.test_stackless import StacklessTest
 from pypy.translator.c import gc
 
@@ -17,8 +17,7 @@
     Coroutine = Coroutine
 
     def setup_method(self, method):
-        main_costate_getter.costate = None
-        main_costate_getter.costate = None
+        syncstate.reset()
 
     def _freeze_(self):    # for 'self.Coroutine'
         return True
@@ -296,7 +295,7 @@
             def call(self):
                 pass
 
-        costate = main_costate_getter._get_default_costate()
+        costate = Coroutine._get_default_costate()
         costate.current.__class__ = C
         costate.hello_goodbye = 0
 
@@ -315,6 +314,25 @@
         #   hello   main   2
         assert output == 3452
 
+    def test_raise_propagate(self):
+        class T(AbstractThunk):
+            def call(self):
+                raise ValueError
+
+        def ep():
+            c = self.Coroutine()
+            c.bind(T())
+            try:
+                c.switch()
+            except ValueError:
+                return 100
+            else:
+                return -5
+
+        output = self.wrap_stackless_function(ep)
+        assert output == 100
+
+
 TestCoroutine = _TestCoroutine # to activate
 class TestCoroutineOnCPython(_TestCoroutine):
     def wrap_stackless_function(self, func):



More information about the Pypy-commit mailing list