[pypy-commit] pypy stacklet: Propagate exceptions to the main stacklet.

arigo noreply at buildbot.pypy.org
Sat Aug 6 12:31:16 CEST 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: stacklet
Changeset: r46310:19a78ea517f4
Date: 2011-08-06 11:34 +0200
http://bitbucket.org/pypy/pypy/changeset/19a78ea517f4/

Log:	Propagate exceptions to the main stacklet.

diff --git a/pypy/module/_stacklet/__init__.py b/pypy/module/_stacklet/__init__.py
--- a/pypy/module/_stacklet/__init__.py
+++ b/pypy/module/_stacklet/__init__.py
@@ -12,4 +12,5 @@
 
     interpleveldefs = {
         'newstacklet': 'interp_stacklet.stacklet_new',
+        'Stacklet': 'interp_stacklet.W_Stacklet',
     }
diff --git a/pypy/module/_stacklet/interp_stacklet.py b/pypy/module/_stacklet/interp_stacklet.py
--- a/pypy/module/_stacklet/interp_stacklet.py
+++ b/pypy/module/_stacklet/interp_stacklet.py
@@ -1,17 +1,23 @@
+import sys
 from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.rlib import rstacklet
+from pypy.rlib.objectmodel import we_are_translated
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.executioncontext import ExecutionContext
 from pypy.interpreter.baseobjspace import Wrappable
 from pypy.interpreter.typedef import TypeDef
 from pypy.interpreter.gateway import interp2app
 
+NULLHANDLE = lltype.nullptr(rstacklet.handle.TO)
+
 
 class SThread(object):
     def __init__(self, space):
         w_module = space.getbuiltinmodule('_stacklet')
         self.space = space
         self.w_error = space.getattr(w_module, space.wrap('error'))
+        self.pending_exception = None
+        self.main_stacklet = None
         self.thrd = rstacklet.newthread()
         if not self.thrd:
             raise MemoryError
@@ -23,6 +29,15 @@
             rstacklet.deletethread(thrd)
 
     def new_stacklet_object(self, space, h):
+        if self.pending_exception is not None:
+            e = self.pending_exception
+            self.pending_exception = None
+            if we_are_translated():
+                raise e
+            else:
+                tb = self.pending_tb
+                del self.pending_tb
+                raise e.__class__, e, tb
         if not h:
             start_state.sthread = None
             start_state.w_callable = None
@@ -44,7 +59,9 @@
     def consume_handle(self):
         h = self.h
         if h:
-            self.h = lltype.nullptr(rstacklet.handle.TO)
+            self.h = NULLHANDLE
+            if self is self.sthread.main_stacklet:
+                self.sthread.main_stacklet = None
             return h
         else:
             space = self.sthread.space
@@ -60,6 +77,7 @@
     __module__ = '_stacklet',
     is_pending = interp2app(W_Stacklet.is_pending),
     )
+W_Stacklet.acceptable_as_base_class = False
 
 
 class StartState:
@@ -76,12 +94,29 @@
     start_state.w_callable = None
     start_state.args = None
     #
-    space = sthread.space
-    args = args.prepend(space.wrap(W_Stacklet(sthread, h)))
-    w_result = space.call_args(w_callable, args)
+    try:
+        space = sthread.space
+        stacklet = W_Stacklet(sthread, h)
+        if sthread.main_stacklet is None:
+            sthread.main_stacklet = stacklet
+        args = args.prepend(space.wrap(stacklet))
+        w_result = space.call_args(w_callable, args)
+        #
+        result = space.interp_w(W_Stacklet, w_result)
+        return result.consume_handle()
     #
-    assert isinstance(w_result, W_Stacklet)
-    return w_result.consume_handle()
+    except Exception, e:
+        sthread.pending_exception = e
+        if not we_are_translated():
+            sthread.pending_tb = sys.exc_info()[2]
+        if sthread.main_stacklet is None:
+            main_stacklet_handle = h
+        else:
+            main_stacklet_handle = sthread.main_stacklet.h
+            sthread.main_stacklet.h = NULLHANDLE
+            sthread.main_stacklet = None
+        assert main_stacklet_handle
+        return main_stacklet_handle
 
 def stacklet_new(space, w_callable, __args__):
     ec = space.getexecutioncontext()
diff --git a/pypy/module/_stacklet/test/test_stacklet.py b/pypy/module/_stacklet/test/test_stacklet.py
--- a/pypy/module/_stacklet/test/test_stacklet.py
+++ b/pypy/module/_stacklet/test/test_stacklet.py
@@ -17,3 +17,16 @@
         h = newstacklet(empty_callback)
         assert h is None
         assert seen == [1]
+
+    def test_bogus_return_value(self):
+        from _stacklet import error, newstacklet
+        #
+        def empty_callback(h):
+            assert h.is_pending()
+            seen.append(h)
+            return 42
+        #
+        seen = []
+        raises(TypeError, newstacklet, empty_callback)
+        assert len(seen) == 1
+        assert not seen[0].is_pending()


More information about the pypy-commit mailing list