[pypy-commit] pypy stm-gc: Start a ThreadLocal object. See comments.
arigo
noreply at buildbot.pypy.org
Sat Apr 28 11:27:48 CEST 2012
Author: Armin Rigo <arigo at tunes.org>
Branch: stm-gc
Changeset: r54784:588d378678ed
Date: 2012-04-28 10:17 +0200
http://bitbucket.org/pypy/pypy/changeset/588d378678ed/
Log: Start a ThreadLocal object. See comments.
diff --git a/pypy/rlib/rstm.py b/pypy/rlib/rstm.py
--- a/pypy/rlib/rstm.py
+++ b/pypy/rlib/rstm.py
@@ -3,6 +3,7 @@
from pypy.rpython.annlowlevel import llhelper, cast_instance_to_base_ptr
from pypy.rpython.annlowlevel import base_ptr_lltype, cast_base_ptr_to_instance
from pypy.rlib.objectmodel import keepalive_until_here, we_are_translated
+from pypy.rlib.objectmodel import specialize
from pypy.rlib.debug import ll_assert
from pypy.rlib.nonconst import NonConstant
from pypy.translator.stm.stmgcintf import StmOperations
@@ -219,3 +220,43 @@
def _stm_thread_stopping():
llop.stm_thread_stopping(lltype.Void)
+
+
+class ThreadLocal(object):
+ """
+ A thread-local container. Use only for one or a few static places,
+ e.g. the ExecutionContext in the PyPy interpreter; and store any
+ number of stuff on the ExecutionContext instead. The point of this
+ is to have proper GC support: if at the end of a transaction some
+ objects are only reachable via a ThreadLocal object, then these
+ objects don't need to be turned GLOBAL. It avoids the overhead of
+ STM, notably the two copies that are needed for every transaction
+ that changes a GLOBAL object.
+ """
+ STMTHREADLOCAL = lltype.Struct('StmThreadLocal',
+ ('content', base_ptr_lltype()),
+ hints={'stm_thread_local': True})
+
+ def __init__(self, Class):
+ assert not we_are_translated(), (
+ "You can only have a small number of ThreadLocal() instances"
+ " built during translation.")
+ self.Class = Class
+ self.threadlocal = lltype.malloc(self.STMTHREADLOCAL, immortal=True)
+
+ def _freeze_(self):
+ return True # but the thread-local value can be read and written
+
+ @specialize.arg(0)
+ def getvalue(self):
+ """Read the thread-local value.
+ It can be either None (the default) or an instance of self.Class."""
+ ptr = self.threadlocal.content
+ return cast_base_ptr_to_instance(self.Class, ptr)
+
+ @specialize.arg(0)
+ def setvalue(self, value):
+ """Write the thread-local value."""
+ assert value is None or isinstance(value, self.Class)
+ ptr = cast_instance_to_base_ptr(value)
+ self.threadlocal.content = ptr
diff --git a/pypy/rlib/test/test_rstm.py b/pypy/rlib/test/test_rstm.py
--- a/pypy/rlib/test/test_rstm.py
+++ b/pypy/rlib/test/test_rstm.py
@@ -117,3 +117,20 @@
def run(self):
return [FooBar() for i in range(10)]
py.test.raises(MyException, rstm.run_all_transactions, DoInOrder())
+
+def test_threadlocal():
+ # not testing the thread-local factor, but only the general interface
+ class Point:
+ def __init__(self, x, y):
+ self.x = x
+ self.y = y
+ p1 = Point(10, 2)
+ p2 = Point(-1, 0)
+ tl = rstm.ThreadLocal(Point)
+ assert tl.getvalue() is None
+ tl.setvalue(p1)
+ assert tl.getvalue() is p1
+ tl.setvalue(p2)
+ assert tl.getvalue() is p2
+ tl.setvalue(None)
+ assert tl.getvalue() is None
More information about the pypy-commit
mailing list