[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