[pypy-svn] r56236 - pypy/dist/pypy/rpython/lltypesystem

arigo at codespeak.net arigo at codespeak.net
Wed Jul 2 13:14:48 CEST 2008


Author: arigo
Date: Wed Jul  2 13:14:47 2008
New Revision: 56236

Modified:
   pypy/dist/pypy/rpython/lltypesystem/rffi.py
Log:
A better approach: this should guarantee more or less
by construction that no gc operation occurs while the GIL
is released.  See comments.


Modified: pypy/dist/pypy/rpython/lltypesystem/rffi.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/rffi.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/rffi.py	Wed Jul  2 13:14:47 2008
@@ -101,6 +101,43 @@
         # sandboxsafe is a hint for "too-small-ness" (e.g. math functions).
         invoke_around_handlers = not sandboxsafe
 
+    if invoke_around_handlers:
+        # The around-handlers are releasing the GIL in a threaded pypy.
+        # We need tons of care to ensure that no GC operation and no
+        # exception checking occurs while the GIL is released.
+
+        # The actual call is done by this small piece of non-inlinable
+        # generated code in order to avoid seeing any GC pointer:
+        # neither '*args' nor the GC objects originally passed in as
+        # argument to wrapper(), if any (e.g. RPython strings).
+
+        argnames = ', '.join(['a%d' % i for i in range(len(args))])
+        source = py.code.Source("""
+            def call_external_function(%(argnames)s):
+                before = aroundstate.before
+                after = aroundstate.after
+                if before: before()
+                # NB. it is essential that no exception checking occurs here!
+                res = funcptr(%(argnames)s)
+                if after: after()
+                return res
+        """ % locals())
+        miniglobals = {'aroundstate': aroundstate,
+                       'funcptr':     funcptr,
+                       }
+        exec source.compile() in miniglobals
+        call_external_function = miniglobals['call_external_function']
+        call_external_function._dont_inline_ = True
+        call_external_function._annspecialcase_ = 'specialize:ll'
+        call_external_function = func_with_new_name(call_external_function,
+                                                    'ccall_' + name)
+        # don't inline, as a hack to guarantee that no GC pointer is alive
+        # anywhere in call_external_function
+    else:
+        # if we don't have to invoke the aroundstate, we can just call
+        # the low-level function pointer carelessly
+        call_external_function = funcptr
+
     unrolling_arg_tps = unrolling_iterable(enumerate(args))
     def wrapper(*args):
         # XXX the next line is a workaround for the annotation bug
@@ -140,19 +177,7 @@
                         arg = cast(TARGET, arg)
             real_args = real_args + (arg,)
             to_free = to_free + (freeme,)
-        if invoke_around_handlers:
-            before = aroundstate.before
-            after = aroundstate.after
-            if before: before()
-            # NB. it is essential that no exception checking occurs after
-            # the call to before(), because we don't have the GIL any more!
-            # It is also essential that no GC pointer is alive between now
-            # and the end of the function, so that the external function
-            # calls below don't need to be guarded by GC shadow stack logic
-            # that would crash if not protected by the GIL!
-        res = funcptr(*real_args)
-        if invoke_around_handlers:
-            if after: after()
+        res = call_external_function(*real_args)
         for i, TARGET in unrolling_arg_tps:
             if to_free[i]:
                 lltype.free(to_free[i], flavor='raw')
@@ -163,12 +188,7 @@
                 return cast(lltype.Unsigned, res)
         return res
     wrapper._annspecialcase_ = 'specialize:ll'
-    if invoke_around_handlers:
-        # don't inline, as a hack to guarantee that no GC pointer is alive
-        # in the final part of the wrapper
-        wrapper._dont_inline_ = True
-    else:
-        wrapper._always_inline_ = True
+    wrapper._always_inline_ = True
     # for debugging, stick ll func ptr to that
     wrapper._ptr = funcptr
 



More information about the Pypy-commit mailing list