[pypy-svn] r55351 - in pypy/branch/gc+thread/pypy: module/thread module/thread/test rlib rpython/lltypesystem rpython/memory/gctransform translator/c/src

arigo at codespeak.net arigo at codespeak.net
Wed May 28 15:57:44 CEST 2008


Author: arigo
Date: Wed May 28 15:57:43 2008
New Revision: 55351

Modified:
   pypy/branch/gc+thread/pypy/module/thread/gil.py
   pypy/branch/gc+thread/pypy/module/thread/ll_thread.py
   pypy/branch/gc+thread/pypy/module/thread/test/test_gil.py
   pypy/branch/gc+thread/pypy/module/thread/test/test_ll_thread.py
   pypy/branch/gc+thread/pypy/rlib/rposix.py
   pypy/branch/gc+thread/pypy/rpython/lltypesystem/rffi.py
   pypy/branch/gc+thread/pypy/rpython/memory/gctransform/framework.py
   pypy/branch/gc+thread/pypy/translator/c/src/thread.h
Log:
Get rid of fused_release_acquire, and replace it simply by a
GIL-releasing call to an external function that does nothing.

That's about the only cleanup in this checkin; the rest is
pile upon pile of fragile hacking :-(


Modified: pypy/branch/gc+thread/pypy/module/thread/gil.py
==============================================================================
--- pypy/branch/gc+thread/pypy/module/thread/gil.py	(original)
+++ pypy/branch/gc+thread/pypy/module/thread/gil.py	Wed May 28 15:57:43 2008
@@ -48,12 +48,10 @@
     def yield_thread(self):
         """Notification that the current thread is between two bytecodes:
         release the GIL for a little while."""
-        ll_GIL = self.ll_GIL
-        # Other threads can run between the release() and the acquire().
-        # This is a single external function so that we are sure that nothing
-        # occurs between the release and the acquire, e.g. no GC operation.
-        thread.fused_release_acquire_NOAUTO(ll_GIL)
-        thread.gc_thread_run()
+        # Other threads can run between the release() and the acquire()
+        # implicit in the following external function call (which has
+        # otherwise no effect).
+        thread.yield_thread()
 
 
 class GILReleaseAction(Action):
@@ -83,9 +81,11 @@
     e = get_errno()
     thread.release_NOAUTO(spacestate.ll_GIL)
     set_errno(e)
+before_external_call._gctransformer_hint_cannot_collect_ = True
 
 def after_external_call():
     e = get_errno()
     thread.acquire_NOAUTO(spacestate.ll_GIL, True)
     thread.gc_thread_run()
     set_errno(e)
+after_external_call._gctransformer_hint_cannot_collect_ = True

Modified: pypy/branch/gc+thread/pypy/module/thread/ll_thread.py
==============================================================================
--- pypy/branch/gc+thread/pypy/module/thread/ll_thread.py	(original)
+++ pypy/branch/gc+thread/pypy/module/thread/ll_thread.py	Wed May 28 15:57:43 2008
@@ -27,7 +27,7 @@
                     python_inc],
     export_symbols = ['RPyThreadGetIdent', 'RPyThreadLockInit',
                       'RPyThreadAcquireLock', 'RPyThreadReleaseLock',
-                      'RPyThreadFusedReleaseAcquireLock',]
+                      'RPyThreadYield']
 )
 
 def llexternal(name, args, result, **kwds):
@@ -71,9 +71,9 @@
 c_thread_releaselock_NOAUTO = llexternal('RPyThreadReleaseLock',
                                          [TLOCKP], lltype.Void,
                                          _nowrapper=True)
-c_thread_fused_releaseacquirelock_NOAUTO = llexternal(
-     'RPyThreadFusedReleaseAcquireLock', [TLOCKP], lltype.Void,
-                                         _nowrapper=True)
+
+# this function does nothing apart from releasing the GIL temporarily.
+yield_thread = llexternal('RPyThreadYield', [], lltype.Void, threadsafe=True)
 
 def allocate_lock():
     return Lock(allocate_ll_lock())
@@ -145,11 +145,6 @@
         ll_assert(not acquire_NOAUTO(ll_lock, False), "NOAUTO lock not held!")
     c_thread_releaselock_NOAUTO(ll_lock)
 
-def fused_release_acquire_NOAUTO(ll_lock):
-    if not we_are_translated():
-        ll_assert(not acquire_NOAUTO(ll_lock, False), "NOAUTO lock not held!")
-    c_thread_fused_releaseacquirelock_NOAUTO(ll_lock)
-
 # ____________________________________________________________
 #
 # Thread integration.

Modified: pypy/branch/gc+thread/pypy/module/thread/test/test_gil.py
==============================================================================
--- pypy/branch/gc+thread/pypy/module/thread/test/test_gil.py	(original)
+++ pypy/branch/gc+thread/pypy/module/thread/test/test_gil.py	Wed May 28 15:57:43 2008
@@ -3,6 +3,7 @@
 from pypy.module.thread.test import test_ll_thread
 from pypy.rpython.lltypesystem import rffi
 from pypy.module.thread import ll_thread as thread
+from pypy.rlib.objectmodel import we_are_translated
 
 class FakeEC(object):
     pass
@@ -48,12 +49,14 @@
             subident = thread.start_new_thread(bootstrap, ())
             mainident = thread.get_ident()
             runme()
-            still_waiting = 1000
+            still_waiting = 3000
             while len(state.data) < 2*N:
                 if not still_waiting:
                     raise ValueError("time out")
                 still_waiting -= 1
+                if not we_are_translated(): gil.before_external_call()
                 time.sleep(0.01)
+                if not we_are_translated(): gil.after_external_call()
             i1 = i2 = 0
             for tid, i in state.data:
                 if tid == mainident:

Modified: pypy/branch/gc+thread/pypy/module/thread/test/test_ll_thread.py
==============================================================================
--- pypy/branch/gc+thread/pypy/module/thread/test/test_ll_thread.py	(original)
+++ pypy/branch/gc+thread/pypy/module/thread/test/test_ll_thread.py	Wed May 28 15:57:43 2008
@@ -28,16 +28,6 @@
     else:
         py.test.fail("Did not raise")
 
-def test_fused():
-    l = allocate_ll_lock()
-    acquire_NOAUTO(l, True)
-    fused_release_acquire_NOAUTO(l)
-    could_acquire_again = acquire_NOAUTO(l, False)
-    assert not could_acquire_again
-    release_NOAUTO(l)
-    could_acquire_again = acquire_NOAUTO(l, False)
-    assert could_acquire_again
-
 
 class AbstractThreadTests(AbstractGCTestClass):
     use_threads = True

Modified: pypy/branch/gc+thread/pypy/rlib/rposix.py
==============================================================================
--- pypy/branch/gc+thread/pypy/rlib/rposix.py	(original)
+++ pypy/branch/gc+thread/pypy/rlib/rposix.py	Wed May 28 15:57:43 2008
@@ -1,6 +1,6 @@
 import os
 from pypy.rpython.lltypesystem.rffi import CConstant, CExternVariable, INT
-from pypy.rpython.lltypesystem import lltype, ll2ctypes
+from pypy.rpython.lltypesystem import lltype, ll2ctypes, rffi
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 from pypy.rlib.rarithmetic import intmask
 
@@ -22,12 +22,19 @@
     includes=['errno.h']
 )
 
-_get_errno, set_errno = CExternVariable(INT, 'errno', errno_eci,
-                                        CConstantErrno, sandboxsafe=True)
+_get_errno, _set_errno = CExternVariable(INT, 'errno', errno_eci,
+                                         CConstantErrno, sandboxsafe=True,
+                                         _nowrapper=True)
+# the default wrapper for set_errno is not suitable for use in critical places
+# like around GIL handling logic, so we provide our own wrappers.
 
 def get_errno():
     return intmask(_get_errno())
 
+def set_errno(errno):
+    _set_errno(rffi.cast(INT, errno))
+
+
 def closerange(fd_low, fd_high):
     # this behaves like os.closerange() from Python 2.6.
     for fd in xrange(fd_low, fd_high):

Modified: pypy/branch/gc+thread/pypy/rpython/lltypesystem/rffi.py
==============================================================================
--- pypy/branch/gc+thread/pypy/rpython/lltypesystem/rffi.py	(original)
+++ pypy/branch/gc+thread/pypy/rpython/lltypesystem/rffi.py	Wed May 28 15:57:43 2008
@@ -146,6 +146,10 @@
             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()
@@ -159,7 +163,9 @@
                 return cast(lltype.Unsigned, res)
         return res
     wrapper._annspecialcase_ = 'specialize:ll'
-    wrapper._always_inline_ = True
+    # 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
     # for debugging, stick ll func ptr to that
     wrapper._ptr = funcptr
 
@@ -382,7 +388,7 @@
     return lltype.Ptr(COpaque(*args, **kwds))
 
 def CExternVariable(TYPE, name, eci, _CConstantClass=CConstant,
-                    sandboxsafe=False):
+                    sandboxsafe=False, _nowrapper=False):
     """Return a pair of functions - a getter and a setter - to access
     the given global C variable.
     """
@@ -421,9 +427,10 @@
     ))
 
     getter = llexternal(getter_name, [], TYPE, compilation_info=new_eci,
-                        sandboxsafe=sandboxsafe)
+                        sandboxsafe=sandboxsafe, _nowrapper=_nowrapper)
     setter = llexternal(setter_name, [TYPE], lltype.Void,
-                        compilation_info=new_eci, sandboxsafe=sandboxsafe)
+                        compilation_info=new_eci, sandboxsafe=sandboxsafe,
+                        _nowrapper=_nowrapper)
     return getter, setter
 
 # char, represented as a Python character

Modified: pypy/branch/gc+thread/pypy/rpython/memory/gctransform/framework.py
==============================================================================
--- pypy/branch/gc+thread/pypy/rpython/memory/gctransform/framework.py	(original)
+++ pypy/branch/gc+thread/pypy/rpython/memory/gctransform/framework.py	Wed May 28 15:57:43 2008
@@ -22,6 +22,16 @@
 
 
 class CollectAnalyzer(graphanalyze.GraphAnalyzer):
+
+    def analyze_direct_call(self, graph, seen=None):
+        try:
+            if graph.func._gctransformer_hint_cannot_collect_:
+                return False
+        except AttributeError:
+            pass
+        return graphanalyze.GraphAnalyzer.analyze_direct_call(self, graph,
+                                                              seen)
+    
     def operation_is_true(self, op):
         if op.opname in ('malloc', 'malloc_varsize'):
             flags = op.args[1].value

Modified: pypy/branch/gc+thread/pypy/translator/c/src/thread.h
==============================================================================
--- pypy/branch/gc+thread/pypy/translator/c/src/thread.h	(original)
+++ pypy/branch/gc+thread/pypy/translator/c/src/thread.h	Wed May 28 15:57:43 2008
@@ -44,17 +44,13 @@
 
 #endif
 
-/* common helper: this is a single external function so that we are
-   sure that nothing occurs between the release and the acquire,
-   e.g. no GC operation. */
-
-void RPyThreadFusedReleaseAcquireLock(struct RPyOpaque_ThreadLock *lock);
+/* common helper: this does nothing, but is called with the GIL released.
+   This gives other threads a chance to grab the GIL and run. */
+void RPyThreadYield(void);
 
 #ifndef PYPY_NOT_MAIN_FILE
-void RPyThreadFusedReleaseAcquireLock(struct RPyOpaque_ThreadLock *lock)
+void RPyThreadYield(void)
 {
-	RPyThreadReleaseLock(lock);
-	RPyThreadAcquireLock(lock, 1);
 }
 #endif
 



More information about the Pypy-commit mailing list