[pypy-commit] pypy stmgc-c8: Change the implementation method of threadlocalproperty().
arigo
noreply at buildbot.pypy.org
Tue Jun 23 12:02:18 CEST 2015
Author: Armin Rigo <arigo at tunes.org>
Branch: stmgc-c8
Changeset: r78253:d3e128694145
Date: 2015-06-23 12:02 +0200
http://bitbucket.org/pypy/pypy/changeset/d3e128694145/
Log: Change the implementation method of threadlocalproperty(). Now it
shouldn't give conflicts the first time the property is accessed on
a given object.
diff --git a/lib_pypy/_weakkeyiddict.py b/lib_pypy/_weakkeyiddict.py
new file mode 100644
--- /dev/null
+++ b/lib_pypy/_weakkeyiddict.py
@@ -0,0 +1,60 @@
+# Copied and adapted from lib-python/2.7/weakref.py.
+# In PyPy (at least -STM), this is not used: a more
+# efficient version is found in the _weakref module.
+
+import UserDict, weakref
+
+
+class idref(weakref.ref):
+
+ def __eq__(self, other):
+ if self is other:
+ return True
+ if not isinstance(other, idref):
+ return NotImplementedError
+ s = self()
+ o = other()
+ return s is o is not None
+
+ def __hash__(self):
+ try:
+ return self._hash_cache
+ except AttributeError:
+ self._hash_cache = id(self())
+ return self._hash_cache
+
+
+class weakkeyiddict(object):
+ """ Mapping class that references keys weakly.
+ In addition, uses the identity of the keys, rather than the equality.
+ (Only a subset of the dict interface is available.)
+ """
+
+ def __init__(self):
+ self.data = {}
+ def remove(k, selfref=weakref.ref(self)):
+ self = selfref()
+ if self is not None:
+ del self.data[k]
+ self._remove = remove
+
+ def __delitem__(self, key):
+ del self.data[idref(key)]
+
+ def __getitem__(self, key):
+ return self.data[idref(key)]
+
+ def __setitem__(self, key, value):
+ self.data[idref(key, self._remove)] = value
+
+ def get(self, key, default=None):
+ return self.data.get(idref(key),default)
+
+ def __contains__(self, key):
+ return idref(key) in self.data
+
+ def pop(self, key, *args):
+ return self.data.pop(idref(key), *args)
+
+ def setdefault(self, key, default=None):
+ return self.data.setdefault(idref(key, self._remove),default)
diff --git a/lib_pypy/transaction.py b/lib_pypy/transaction.py
--- a/lib_pypy/transaction.py
+++ b/lib_pypy/transaction.py
@@ -52,6 +52,12 @@
from time import time, clock
try:
+ from _weakref import weakkeyiddict
+except ImportError:
+ # Not a STM-enabled PyPy.
+ from _weakkeyiddict import weakkeyiddict
+
+try:
from pypystm import queue, Empty
except ImportError:
from Queue import Queue as queue
@@ -232,29 +238,32 @@
class threadlocalproperty(object):
def __init__(self, default_factory=None):
self.tl_default_factory = default_factory
- self.tl_name = intern('tlprop.%d' % id(self))
+ self.tl_local = thread._local()
- def tl_get(self, obj):
+ def tl_wrefs(self):
try:
- return obj._threadlocalproperties
+ return self.tl_local.wrefs
except AttributeError:
- return obj.__dict__.setdefault('_threadlocalproperties',
- thread._local())
+ self.tl_local.wrefs = wrefs = weakkeyiddict()
+ return wrefs
def __get__(self, obj, cls=None):
if obj is None:
return self
+ wrefs = self.tl_wrefs()
try:
- return getattr(self.tl_get(obj), self.tl_name)
- except AttributeError:
+ return wrefs[obj]
+ except KeyError:
if self.tl_default_factory is None:
- raise
- result = self.tl_default_factory()
- setattr(self.tl_get(obj), self.tl_name, result)
+ raise AttributeError
+ wrefs[obj] = result = self.tl_default_factory()
return result
def __set__(self, obj, value):
- setattr(self.tl_get(obj), self.tl_name, value)
+ self.tl_wrefs()[obj] = value
def __delete__(self, obj):
- delattr(self.tl_get(obj), self.tl_name)
+ try:
+ del self.tl_wrefs()[obj]
+ except KeyError:
+ raise AttributeError
More information about the pypy-commit
mailing list