[pypy-commit] pypy stm-thread: Support for thread.atomic also for pypy without stm.
arigo
noreply at buildbot.pypy.org
Sat May 12 20:30:20 CEST 2012
Author: Armin Rigo <arigo at tunes.org>
Branch: stm-thread
Changeset: r55064:149d8955d1c8
Date: 2012-05-12 20:29 +0200
http://bitbucket.org/pypy/pypy/changeset/149d8955d1c8/
Log: Support for thread.atomic also for pypy without stm.
diff --git a/pypy/module/thread/atomic.py b/pypy/module/thread/atomic.py
--- a/pypy/module/thread/atomic.py
+++ b/pypy/module/thread/atomic.py
@@ -1,18 +1,26 @@
from pypy.interpreter.error import OperationError
-from pypy.rlib.rstm import increment_atomic, decrement_atomic, is_atomic
from pypy.module.thread.error import wrap_thread_error
def atomic_enter(space):
- if not space.config.translation.stm:
- raise wrap_thread_error(space,
- "atomic.__enter__(): STM not available")
- increment_atomic()
+ if space.config.translation.stm:
+ from pypy.rlib.rstm import increment_atomic
+ increment_atomic()
+ else:
+ giltl = space.threadlocals
+ giltl.is_atomic += 1
+ space.threadlocals.set_gil_releasing_calls()
def atomic_exit(space, w_ignored1=None, w_ignored2=None, w_ignored3=None):
- if not space.config.translation.stm:
- raise wrap_thread_error(space,
- "atomic.__exit__(): STM not available")
- if not is_atomic():
- raise wrap_thread_error(space,
- "atomic.__exit__(): more exits than enters")
- decrement_atomic()
+ if space.config.translation.stm:
+ from pypy.rlib.rstm import decrement_atomic, is_atomic
+ if is_atomic():
+ decrement_atomic()
+ return
+ else:
+ giltl = space.threadlocals
+ if giltl.is_atomic > 0:
+ giltl.is_atomic -= 1
+ space.threadlocals.set_gil_releasing_calls()
+ return
+ raise wrap_thread_error(space,
+ "atomic.__exit__(): more exits than enters")
diff --git a/pypy/module/thread/gil.py b/pypy/module/thread/gil.py
--- a/pypy/module/thread/gil.py
+++ b/pypy/module/thread/gil.py
@@ -11,12 +11,13 @@
from pypy.module.thread.error import wrap_thread_error
from pypy.interpreter.executioncontext import PeriodicAsyncAction
from pypy.module.thread.threadlocals import OSThreadLocals
-from pypy.rlib.objectmodel import invoke_around_extcall
+from pypy.rlib.objectmodel import invoke_around_extcall, has_around_extcall
from pypy.rlib.rposix import get_errno, set_errno
class GILThreadLocals(OSThreadLocals):
"""A version of OSThreadLocals that enforces a GIL."""
gil_ready = False
+ is_atomic = 0
_immutable_fields_ = ['gil_ready?']
def initialize(self, space):
@@ -42,9 +43,20 @@
# test_lock_again after the global state was cleared by
# test_compile_lock. As a workaround, we repatch these global
# fields systematically.
- invoke_around_extcall(before_external_call, after_external_call)
+ self.set_gil_releasing_calls()
return result
+ def set_gil_releasing_calls(self):
+ if self.is_atomic == 0:
+ # not running atomically so far, so we register the
+ # functions that will be called around external calls
+ invoke_around_extcall(before_external_call, after_external_call)
+ else:
+ # running atomically: we have the GIL here, so if we
+ # just un-register the functions, we won't release the GIL
+ # any more.
+ invoke_around_extcall(None, None)
+
def reinit_threads(self, space):
if self.gil_ready:
self.gil_ready = False
@@ -109,9 +121,10 @@
# explicitly release the gil, in a way that tries to give more
# priority to other threads (as opposed to continuing to run in
# the same thread).
- if thread.gil_yield_thread():
- thread.gc_thread_run()
- spacestate.after_thread_switch()
+ if has_around_extcall():
+ if thread.gil_yield_thread():
+ thread.gc_thread_run()
+ spacestate.after_thread_switch()
do_yield_thread._gctransformer_hint_close_stack_ = True
do_yield_thread._dont_reach_me_in_del_ = True
do_yield_thread._dont_inline_ = True
diff --git a/pypy/module/thread/test/test_atomic.py b/pypy/module/thread/test/test_atomic.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/thread/test/test_atomic.py
@@ -0,0 +1,15 @@
+from __future__ import with_statement
+from pypy.module.thread.test.support import GenericTestThread
+
+
+class AppTestAtomic(GenericTestThread):
+
+ def test_simple(self):
+ import thread
+ with thread.atomic:
+ pass
+ try:
+ with thread.atomic:
+ raise ValueError
+ except ValueError:
+ pass
diff --git a/pypy/rlib/objectmodel.py b/pypy/rlib/objectmodel.py
--- a/pypy/rlib/objectmodel.py
+++ b/pypy/rlib/objectmodel.py
@@ -489,8 +489,8 @@
# the 'aroundstate' contains regular function and not ll pointers to them,
# but let's call llhelper() anyway to force their annotation
from pypy.rpython.annlowlevel import llhelper
- llhelper(rffi.AroundFnPtr, before)
- llhelper(rffi.AroundFnPtr, after)
+ if before is not None: llhelper(rffi.AroundFnPtr, before)
+ if after is not None: llhelper(rffi.AroundFnPtr, after)
# do the same thing about enter/leave_callback
if enter_callback is not None:
rffi.aroundstate.enter_callback = enter_callback
@@ -503,6 +503,10 @@
from pypy.rpython.lltypesystem import rffi
return rffi.stackcounter.stacks_counter > 1
+def has_around_extcall():
+ from pypy.rpython.lltypesystem import rffi
+ return rffi.aroundstate.before is not None
+
class UnboxedValue(object):
"""A mixin class to use for classes that have exactly one field which
More information about the pypy-commit
mailing list