[pypy-commit] pypy stmgc-c7: Start a built-in module "_stm".
arigo
noreply at buildbot.pypy.org
Mon Nov 10 14:56:47 CET 2014
Author: Armin Rigo <arigo at tunes.org>
Branch: stmgc-c7
Changeset: r74426:a94a7b675578
Date: 2014-11-10 14:56 +0100
http://bitbucket.org/pypy/pypy/changeset/a94a7b675578/
Log: Start a built-in module "_stm".
diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -34,7 +34,7 @@
self.w_profilefuncarg = None
#
if self.space.config.translation.stm:
- from pypy.module.thread.stm import initialize_execution_context
+ from pypy.module._stm.ec import initialize_execution_context
initialize_execution_context(self)
def gettopframe(self):
diff --git a/pypy/module/_stm/__init__.py b/pypy/module/_stm/__init__.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_stm/__init__.py
@@ -0,0 +1,11 @@
+
+# Package initialisation
+from pypy.interpreter.mixedmodule import MixedModule
+
+class Module(MixedModule):
+ appleveldefs = {
+ }
+
+ interpleveldefs = {
+ 'local': 'local.STMLocal',
+ }
diff --git a/pypy/module/_stm/ec.py b/pypy/module/_stm/ec.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_stm/ec.py
@@ -0,0 +1,29 @@
+"""
+Attach extra STM-only attributes to the ExecutionContext.
+"""
+
+from pypy.interpreter.executioncontext import ExecutionContext
+from pypy.interpreter.gateway import W_Root
+
+
+class FakeWeakKeyDictionary:
+ # Only used if we don't have weakrefs.
+ # Then thread._local instances will leak, but too bad.
+ def __init__(self):
+ self.d = {}
+ def get(self, key):
+ return self.d.get(key, None)
+ def set(self, key, value):
+ self.d[key] = value
+
+def initialize_execution_context(ec):
+ """Called from ExecutionContext.__init__()."""
+ if ec.space.config.translation.rweakref:
+ from rpython.rlib import rweakref
+ from pypy.module._stm.local import STMLocal
+ ec._thread_local_dicts = rweakref.RWeakKeyDictionary(STMLocal, W_Root)
+ else:
+ ec._thread_local_dicts = FakeWeakKeyDictionary()
+ if ec.space.config.objspace.std.withmethodcache:
+ from pypy.objspace.std.typeobject import MethodCache
+ ec._methodcache = MethodCache(ec.space)
diff --git a/pypy/module/_stm/local.py b/pypy/module/_stm/local.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_stm/local.py
@@ -0,0 +1,75 @@
+"""
+The '_stm.local' class, used for 'thread._local' with STM.
+"""
+
+from pypy.interpreter.gateway import W_Root, interp2app
+from pypy.interpreter.typedef import TypeDef, GetSetProperty, descr_get_dict
+from rpython.rlib import jit
+from rpython.rlib.objectmodel import we_are_translated
+
+
+def _fill_untranslated(ec):
+ if not we_are_translated() and not hasattr(ec, '_thread_local_dicts'):
+ from pypy.module._stm.ec import initialize_execution_context
+ initialize_execution_context(ec)
+
+
+class STMLocal(W_Root):
+ """Thread-local data"""
+
+ @jit.dont_look_inside
+ def __init__(self, space, initargs):
+ self.space = space
+ self.initargs = initargs
+ # The app-level __init__() will be called by the general
+ # instance-creation logic. It causes getdict() to be
+ # immediately called. If we don't prepare and set a w_dict
+ # for the current thread, then this would in cause getdict()
+ # to call __init__() a second time.
+ ec = space.getexecutioncontext()
+ _fill_untranslated(ec)
+ w_dict = space.newdict(instance=True)
+ ec._thread_local_dicts.set(self, w_dict)
+
+ @jit.dont_look_inside
+ def create_new_dict(self, ec):
+ # create a new dict for this thread
+ space = self.space
+ w_dict = space.newdict(instance=True)
+ ec._thread_local_dicts.set(self, w_dict)
+ # call __init__
+ try:
+ w_self = space.wrap(self)
+ w_type = space.type(w_self)
+ w_init = space.getattr(w_type, space.wrap("__init__"))
+ space.call_obj_args(w_init, w_self, self.initargs)
+ except:
+ # failed, forget w_dict and propagate the exception
+ ec._thread_local_dicts.set(self, None)
+ raise
+ # ready
+ return w_dict
+
+ def getdict(self, space):
+ ec = space.getexecutioncontext()
+ _fill_untranslated(ec)
+ w_dict = ec._thread_local_dicts.get(self)
+ if w_dict is None:
+ w_dict = self.create_new_dict(ec)
+ return w_dict
+
+ def descr_local__new__(space, w_subtype, __args__):
+ local = space.allocate_instance(STMLocal, w_subtype)
+ STMLocal.__init__(local, space, __args__)
+ return space.wrap(local)
+
+ def descr_local__init__(self, space):
+ # No arguments allowed
+ pass
+
+STMLocal.typedef = TypeDef("_stm.local",
+ __doc__ = "Thread-local data",
+ __new__ = interp2app(STMLocal.descr_local__new__.im_func),
+ __init__ = interp2app(STMLocal.descr_local__init__),
+ __dict__ = GetSetProperty(descr_get_dict, cls=STMLocal),
+ )
diff --git a/pypy/module/_stm/lock.py b/pypy/module/_stm/lock.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_stm/lock.py
@@ -0,0 +1,21 @@
+from pypy.module.thread.error import wrap_thread_error
+
+
+class STMLock(rthread.Lock):
+ def __init__(self, space, ll_lock):
+ rthread.Lock.__init__(self, ll_lock)
+ self.space = space
+
+ def acquire(self, flag):
+ if rstm.is_atomic():
+ acquired = rthread.Lock.acquire(self, False)
+ if flag and not acquired:
+ raise wrap_thread_error(self.space,
+ "deadlock: an atomic transaction tries to acquire "
+ "a lock that is already acquired. See pypy/doc/stm.rst.")
+ else:
+ acquired = rthread.Lock.acquire(self, flag)
+ return acquired
+
+def allocate_stm_lock(space):
+ return STMLock(space, rthread.allocate_ll_lock())
diff --git a/pypy/module/thread/test/__init__.py b/pypy/module/_stm/test/__init__.py
copy from pypy/module/thread/test/__init__.py
copy to pypy/module/_stm/test/__init__.py
diff --git a/pypy/module/thread/test/test_stm.py b/pypy/module/_stm/test/test_local.py
rename from pypy/module/thread/test/test_stm.py
rename to pypy/module/_stm/test/test_local.py
--- a/pypy/module/thread/test/test_stm.py
+++ b/pypy/module/_stm/test/test_local.py
@@ -2,10 +2,12 @@
class AppTestSTMLocal(test_local.AppTestLocal):
+ spaceconfig = test_local.AppTestLocal.spaceconfig.copy()
+ spaceconfig['usemodules'] += ('_stm',)
def setup_class(cls):
test_local.AppTestLocal.setup_class.im_func(cls)
cls.w__local = cls.space.appexec([], """():
- import thread
- return thread._untranslated_stmlocal
+ import _stm
+ return _stm.local
""")
diff --git a/pypy/module/_stm/threadlocals.py b/pypy/module/_stm/threadlocals.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_stm/threadlocals.py
@@ -0,0 +1,42 @@
+"""
+An STM-friendly subclass of OSThreadLocals.
+"""
+
+from pypy.module.thread.threadlocals import OSThreadLocals
+from rpython.rlib import rstm
+from rpython.rlib.objectmodel import invoke_around_extcall
+
+
+class STMThreadLocals(OSThreadLocals):
+ threads_running = False
+ _immutable_fields_ = ['threads_running?']
+
+ def initialize(self, space):
+ """NOT_RPYTHON: set up a mechanism to send to the C code the value
+ set by space.actionflag.setcheckinterval()."""
+ #
+ def setcheckinterval_callback():
+ self.configure_transaction_length(space)
+ #
+ assert space.actionflag.setcheckinterval_callback is None
+ space.actionflag.setcheckinterval_callback = setcheckinterval_callback
+
+ # XXX?
+ #def getallvalues(self):
+ # raise ValueError
+
+ def setup_threads(self, space):
+ if not self.threads_running:
+ # invalidate quasi-immutable if we have threads:
+ self.threads_running = True
+ self.configure_transaction_length(space)
+ invoke_around_extcall(rstm.before_external_call,
+ rstm.after_external_call,
+ rstm.enter_callback_call,
+ rstm.leave_callback_call)
+
+ def configure_transaction_length(self, space):
+ if self.threads_running:
+ interval = space.actionflag.getcheckinterval()
+ rstm.set_transaction_length(interval / 10000.0)
+
diff --git a/pypy/module/thread/__init__.py b/pypy/module/thread/__init__.py
--- a/pypy/module/thread/__init__.py
+++ b/pypy/module/thread/__init__.py
@@ -45,5 +45,3 @@
self.extra_interpdef('_local', 'stm.STMLocal')
else:
self.extra_interpdef('_local', 'os_local.Local')
- if not self.space.config.translating:
- self.extra_interpdef('_untranslated_stmlocal', 'stm.STMLocal')
diff --git a/pypy/module/thread/stm.py b/pypy/module/thread/stm.py
--- a/pypy/module/thread/stm.py
+++ b/pypy/module/thread/stm.py
@@ -1,161 +1,8 @@
"""
-Software Transactional Memory emulation of the GIL.
-
-XXX this module may contain near-duplicated code from the non-STM variants
+Redirect some classes from pypy.module._stm.
"""
-from pypy.module.thread.threadlocals import OSThreadLocals
-from pypy.module.thread.error import wrap_thread_error
-from pypy.interpreter.executioncontext import ExecutionContext
-from pypy.interpreter.gateway import W_Root, interp2app
-from pypy.interpreter.typedef import TypeDef, GetSetProperty, descr_get_dict
-from rpython.rlib import rthread
-from rpython.rlib import rstm
-from rpython.rlib import jit
-from rpython.rlib.objectmodel import invoke_around_extcall, we_are_translated
+from pypy.module._stm import threadlocals, local
-
-class FakeWeakKeyDictionary:
- # Only used if we don't have weakrefs.
- # Then thread._local instances will leak, but too bad.
- def __init__(self):
- self.d = {}
- def get(self, key):
- return self.d.get(key, None)
- def set(self, key, value):
- self.d[key] = value
-
-
-def initialize_execution_context(ec):
- """Called from ExecutionContext.__init__()."""
- if ec.space.config.translation.rweakref:
- from rpython.rlib import rweakref
- ec._thread_local_dicts = rweakref.RWeakKeyDictionary(STMLocal, W_Root)
- else:
- ec._thread_local_dicts = FakeWeakKeyDictionary()
- if ec.space.config.objspace.std.withmethodcache:
- from pypy.objspace.std.typeobject import MethodCache
- ec._methodcache = MethodCache(ec.space)
-
-def _fill_untranslated(ec):
- if not we_are_translated() and not hasattr(ec, '_thread_local_dicts'):
- initialize_execution_context(ec)
-
-
-class STMThreadLocals(OSThreadLocals):
- threads_running = False
- _immutable_fields_ = ['threads_running?']
-
- def initialize(self, space):
- """NOT_RPYTHON: set up a mechanism to send to the C code the value
- set by space.actionflag.setcheckinterval()."""
- #
- def setcheckinterval_callback():
- self.configure_transaction_length(space)
- #
- assert space.actionflag.setcheckinterval_callback is None
- space.actionflag.setcheckinterval_callback = setcheckinterval_callback
-
- # XXX?
- #def getallvalues(self):
- # raise ValueError
-
- def setup_threads(self, space):
- if not self.threads_running:
- # invalidate quasi-immutable if we have threads:
- self.threads_running = True
- self.configure_transaction_length(space)
- invoke_around_extcall(rstm.before_external_call,
- rstm.after_external_call,
- rstm.enter_callback_call,
- rstm.leave_callback_call)
-
- def configure_transaction_length(self, space):
- if self.threads_running:
- interval = space.actionflag.getcheckinterval()
- rstm.set_transaction_length(interval / 10000.0)
-
-# ____________________________________________________________
-
-
-class STMLock(rthread.Lock):
- def __init__(self, space, ll_lock):
- rthread.Lock.__init__(self, ll_lock)
- self.space = space
-
- def acquire(self, flag):
- if rstm.is_atomic():
- acquired = rthread.Lock.acquire(self, False)
- if flag and not acquired:
- raise wrap_thread_error(self.space,
- "deadlock: an atomic transaction tries to acquire "
- "a lock that is already acquired. See pypy/doc/stm.rst.")
- else:
- acquired = rthread.Lock.acquire(self, flag)
- return acquired
-
-def allocate_stm_lock(space):
- return STMLock(space, rthread.allocate_ll_lock())
-
-# ____________________________________________________________
-
-
-class STMLocal(W_Root):
- """Thread-local data"""
-
- @jit.dont_look_inside
- def __init__(self, space, initargs):
- self.space = space
- self.initargs = initargs
- # The app-level __init__() will be called by the general
- # instance-creation logic. It causes getdict() to be
- # immediately called. If we don't prepare and set a w_dict
- # for the current thread, then this would in cause getdict()
- # to call __init__() a second time.
- ec = space.getexecutioncontext()
- _fill_untranslated(ec)
- w_dict = space.newdict(instance=True)
- ec._thread_local_dicts.set(self, w_dict)
-
- @jit.dont_look_inside
- def create_new_dict(self, ec):
- # create a new dict for this thread
- space = self.space
- w_dict = space.newdict(instance=True)
- ec._thread_local_dicts.set(self, w_dict)
- # call __init__
- try:
- w_self = space.wrap(self)
- w_type = space.type(w_self)
- w_init = space.getattr(w_type, space.wrap("__init__"))
- space.call_obj_args(w_init, w_self, self.initargs)
- except:
- # failed, forget w_dict and propagate the exception
- ec._thread_local_dicts.set(self, None)
- raise
- # ready
- return w_dict
-
- def getdict(self, space):
- ec = space.getexecutioncontext()
- _fill_untranslated(ec)
- w_dict = ec._thread_local_dicts.get(self)
- if w_dict is None:
- w_dict = self.create_new_dict(ec)
- return w_dict
-
- def descr_local__new__(space, w_subtype, __args__):
- local = space.allocate_instance(STMLocal, w_subtype)
- STMLocal.__init__(local, space, __args__)
- return space.wrap(local)
-
- def descr_local__init__(self, space):
- # No arguments allowed
- pass
-
-STMLocal.typedef = TypeDef("thread._local",
- __doc__ = "Thread-local data",
- __new__ = interp2app(STMLocal.descr_local__new__.im_func),
- __init__ = interp2app(STMLocal.descr_local__init__),
- __dict__ = GetSetProperty(descr_get_dict, cls=STMLocal),
- )
+STMThreadLocals = threadlocals.STMThreadLocals
+STMLocal = local.STMLocal
More information about the pypy-commit
mailing list