Commits

Armin Rigo committed 189d570

Replace the aroundstate.after()/aroundstate.before() around callbacks with something more explicit:
aroundstate.enter_callback()/aroundstate.leave_callback(). Allows us to do an annotator-friendly special case
for entering callbacks in case we have a JIT but no threads (yet).

Comments (0)

Files changed (7)

pypy/goal/targetpypystandalone.py

 
     @entrypoint('main', [rffi.CCHARP], c_name='pypy_execute_source')
     def pypy_execute_source(ll_source):
-        after = rffi.aroundstate.after
-        if after: after()
+        rffi.aroundstate.enter_callback()
         source = rffi.charp2str(ll_source)
         res = _pypy_execute_source(source)
-        before = rffi.aroundstate.before
-        if before: before()
+        rffi.aroundstate.leave_callback()
         return rffi.cast(rffi.INT, res)
 
     @entrypoint('main', [rffi.CCHARP, lltype.Signed],
                 c_name='pypy_execute_source_ptr')
     def pypy_execute_source_ptr(ll_source, ll_ptr):
-        after = rffi.aroundstate.after
-        if after: after()
+        rffi.aroundstate.enter_callback()
         source = rffi.charp2str(ll_source)
         space.setitem(w_globals, space.wrap('c_argument'),
                       space.wrap(ll_ptr))
         res = _pypy_execute_source(source)
-        before = rffi.aroundstate.before
-        if before: before()
+        rffi.aroundstate.leave_callback()
         return rffi.cast(rffi.INT, res)        
 
     @entrypoint('main', [], c_name='pypy_init_threads')
         if not space.config.objspace.usemodules.thread:
             return
         os_thread.setup_threads(space)
-        before = rffi.aroundstate.before
-        if before: before()
+        rffi.aroundstate.leave_callback()
 
     @entrypoint('main', [], c_name='pypy_thread_attach')
     def pypy_thread_attach():
         rthread.gc_thread_start()
         os_thread.bootstrapper.nbthreads += 1
         os_thread.bootstrapper.release()
-        before = rffi.aroundstate.before
-        if before: before()
+        rffi.aroundstate.leave_callback()
 
     w_globals = space.newdict()
     space.setitem(w_globals, space.wrap('__builtins__'),

pypy/module/cpyext/pystate.py

     state = space.fromcache(InterpreterState)
     tstate = state.swap_thread_state(
         space, lltype.nullptr(PyThreadState.TO))
-    if rffi.aroundstate.before:
-        rffi.aroundstate.before()
+    rffi.aroundstate.leave_callback()
     return tstate
 
 @cpython_api([PyThreadState], lltype.Void)
     NULL.  If the lock has been created, the current thread must not have
     acquired it, otherwise deadlock ensues.  (This function is available even
     when thread support is disabled at compile time.)"""
-    if rffi.aroundstate.after:
-        rffi.aroundstate.after()
+    rffi.aroundstate.enter_callback()
     state = space.fromcache(InterpreterState)
     state.swap_thread_state(space, tstate)
 
     tstate, which should not be NULL.  The lock must have been created earlier.
     If this thread already has the lock, deadlock ensues.  This function is not
     available when thread support is disabled at compile time."""
-    if rffi.aroundstate.after:
-        # After external call is before entering Python
-        rffi.aroundstate.after()
+    rffi.aroundstate.enter_callback()
 
 @cpython_api([PyThreadState], lltype.Void)
 def PyEval_ReleaseThread(space, tstate):
     that it represents the current thread state --- if it isn't, a fatal error is
     reported. This function is not available when thread support is disabled at
     compile time."""
-    if rffi.aroundstate.before:
-        # Before external call is after running Python
-        rffi.aroundstate.before()
+    rffi.aroundstate.leave_callback()
 
 PyGILState_STATE = rffi.COpaquePtr('PyGILState_STATE',
                                    typedef='PyGILState_STATE',
 
 @cpython_api([], PyGILState_STATE, error=CANNOT_FAIL)
 def PyGILState_Ensure(space):
-    if rffi.aroundstate.after:
-        # After external call is before entering Python
-        rffi.aroundstate.after()
+    rffi.aroundstate.enter_callback()
     return 0
 
 @cpython_api([PyGILState_STATE], lltype.Void)
 def PyGILState_Release(space, state):
-    if rffi.aroundstate.before:
-        # Before external call is after running Python
-        rffi.aroundstate.before()
+    rffi.aroundstate.leave_callback()
 
 @cpython_api([], PyInterpreterState, error=CANNOT_FAIL)
 def PyInterpreterState_Head(space):
         raise NoThreads
     # PyThreadState_Get will allocate a new execution context,
     # we need to protect gc and other globals with the GIL.
-    rffi.aroundstate.after()
+    rffi.aroundstate.enter_callback()
     try:
         rthread.gc_thread_start()
         return PyThreadState_Get(space)
     finally:
-        rffi.aroundstate.before()
+        rffi.aroundstate.leave_callback()
 
 @cpython_api([PyThreadState], lltype.Void)
 def PyThreadState_Clear(space, tstate):

rpython/jit/backend/llsupport/callbuilder.py

 from rpython.rlib.clibffi import FFI_DEFAULT_ABI
-from rpython.rlib import objectmodel
+from rpython.rlib import rthread
 
 
 class AbstractCallBuilder(object):
         """Emit a CALL_RELEASE_GIL, including calls to releasegil_addr
         and reacqgil_addr."""
         is_asmgcc = self.asm._is_asmgcc()
-        fastgil = objectmodel.prepare_enter_callback_from_jit(is_asmgcc)
+        fastgil = rthread.get_fastgil_addr_raw(is_asmgcc)
         self.select_call_release_gil_mode()
         self.prepare_arguments()
         self.push_gcmap_for_call_release_gil()

rpython/rlib/objectmodel.py

     from rpython.rtyper.lltypesystem import rffi
     rffi.aroundstate.before = before
     rffi.aroundstate.after = after
+    # For now, 'aroundstate.enter_callback' does something for the non-GIL
+    # case that is also done by the full 'after' callback.  So we can simply
+    # replace it with 'after' when we get one.
+    if after is not None:
+        rffi.aroundstate.enter_callback = after
     # the 'aroundstate' contains regular function and not ll pointers to them,
     # but let's call llhelper() anyway to force their annotation
     from rpython.rtyper.annlowlevel import llhelper
     llhelper(rffi.AroundFnPtr, before)
     llhelper(rffi.AroundFnPtr, after)
 
-def _enter_callback_from_jit():
-    from rpython.rlib import rthread
-    rthread.gil_enter_callback_without_gil()    # no need for errno saving
-
-def prepare_enter_callback_from_jit(is_asmgcc):
-    from rpython.rlib import rthread
-    from rpython.rtyper.lltypesystem import rffi
-    if rffi.aroundstate.after is None:
-        rffi.aroundstate.after = _enter_callback_from_jit
-        from rpython.rtyper.annlowlevel import llhelper
-        llhelper(rffi.AroundFnPtr, _enter_callback_from_jit)
-    return rthread.get_fastgil_addr_raw(is_asmgcc)
-
 def is_in_callback():
     from rpython.rtyper.lltypesystem import rffi
     return rffi.stackcounter.stacks_counter > 1

rpython/rlib/rthread.py

     includes = ['src/thread.h'],
     separate_module_files = [translator_c_dir / 'src' / 'thread.c'],
     include_dirs = [translator_c_dir],
+    post_include_bits = ['''
+#ifndef RPY_FASTGIL
+#  define RPyEnterCallbackWithoutGil()  /* nothing */
+#endif
+'''],
     export_symbols = ['RPyThreadGetIdent', 'RPyThreadLockInit',
                       'RPyThreadAcquireLock', 'RPyThreadAcquireLockTimed',
                       'RPyThreadReleaseLock', 'RPyGilAllocate',

rpython/rtyper/lltypesystem/rffi.py

     source = py.code.Source(r"""
         def wrapper(%(args)s):    # no *args - no GIL for mallocing the tuple
             if aroundstate is not None:
-                after = aroundstate.after
-                if after:
-                    after()
+                aroundstate.enter_callback()
             # from now on we hold the GIL
             stackcounter.stacks_counter += 1
             llop.gc_stack_bottom(lltype.Void)   # marker for trackgcroot.py
                 result = errorcode
             stackcounter.stacks_counter -= 1
             if aroundstate is not None:
-                before = aroundstate.before
-                if before:
-                    before()
+                aroundstate.leave_callback()
             # here we don't hold the GIL any more. As in the wrapper() produced
             # by llexternal, it is essential that no exception checking occurs
-            # after the call to before().
+            # after the call to leave_calback().
             return result
     """ % locals())
     miniglobals = locals().copy()
     return miniglobals['wrapper']
 _make_wrapper_for._annspecialcase_ = 'specialize:memo'
 
+def enter_callback_without_gil():
+    if we_are_translated():
+        from rpython.rlib import rthread
+        rthread.gil_enter_callback_without_gil()
+
 AroundFnPtr = lltype.Ptr(lltype.FuncType([], lltype.Void))
 
 class AroundState:
     def _cleanup_(self):
         self.before = None        # or a regular RPython function
         self.after = None         # or a regular RPython function
+        self.enter_callback = enter_callback_without_gil
+    def leave_callback():
+        before = aroundstate.before   # for now, it's the same
+        if before: before()
+    leave_callback._always_inline_ = True
+    leave_callback = staticmethod(leave_callback)
 aroundstate = AroundState()
 aroundstate._cleanup_()
 

rpython/translator/c/src/thread_pthread.c

         }
     }
 }
-#endif
+#endif  /* RPY_FASTGIL */
 
 void RPyGilAcquire(void)
 {