[pypy-commit] pypy default: merge heads
mattip
noreply at buildbot.pypy.org
Wed May 9 22:55:51 CEST 2012
Author: Matti Picus <matti.picus at gmail.com>
Branch:
Changeset: r54998:d8e00a3ec08d
Date: 2012-05-09 23:55 +0300
http://bitbucket.org/pypy/pypy/changeset/d8e00a3ec08d/
Log: merge heads
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
@@ -18,7 +18,7 @@
'allocate_lock': 'os_lock.allocate_lock',
'allocate': 'os_lock.allocate_lock', # obsolete synonym
'LockType': 'os_lock.Lock',
- #'_local': 'os_local.Local', # only if 'rweakref'
+ '_local': 'os_local.Local',
'error': 'space.fromcache(error.Cache).w_error',
}
@@ -34,8 +34,3 @@
from pypy.module.posix.interp_posix import add_fork_hook
from pypy.module.thread.os_thread import reinit_threads
add_fork_hook('child', reinit_threads)
-
- def setup_after_space_initialization(self):
- """NOT_RPYTHON"""
- if self.space.config.translation.rweakref:
- self.extra_interpdef('_local', 'os_local.Local')
diff --git a/pypy/module/thread/os_local.py b/pypy/module/thread/os_local.py
--- a/pypy/module/thread/os_local.py
+++ b/pypy/module/thread/os_local.py
@@ -1,16 +1,21 @@
-from pypy.rlib.rweakref import RWeakKeyDictionary
+import weakref
+from pypy.rlib import jit
from pypy.interpreter.baseobjspace import Wrappable, W_Root
from pypy.interpreter.executioncontext import ExecutionContext
from pypy.interpreter.typedef import (TypeDef, interp2app, GetSetProperty,
descr_get_dict)
+ExecutionContext._thread_local_objs = None
+
+
class Local(Wrappable):
"""Thread-local data"""
+ @jit.dont_look_inside
def __init__(self, space, initargs):
self.initargs = initargs
- self.dicts = RWeakKeyDictionary(ExecutionContext, W_Root)
+ self.dicts = {} # mapping ExecutionContexts to the wraped dict
# 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
@@ -18,26 +23,42 @@
# to call __init__() a second time.
ec = space.getexecutioncontext()
w_dict = space.newdict(instance=True)
- self.dicts.set(ec, w_dict)
+ self.dicts[ec] = w_dict
+ self._register_in_ec(ec)
+
+ def _register_in_ec(self, ec):
+ if not ec.space.config.translation.rweakref:
+ return # without weakrefs, works but 'dicts' is never cleared
+ if ec._thread_local_objs is None:
+ ec._thread_local_objs = []
+ ec._thread_local_objs.append(weakref.ref(self))
+
+ @jit.dont_look_inside
+ def create_new_dict(self, ec):
+ # create a new dict for this thread
+ space = ec.space
+ w_dict = space.newdict(instance=True)
+ self.dicts[ec] = 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
+ del self.dicts[ec]
+ raise
+ # ready
+ self._register_in_ec(ec)
+ return w_dict
def getdict(self, space):
ec = space.getexecutioncontext()
- w_dict = self.dicts.get(ec)
- if w_dict is None:
- # create a new dict for this thread
- w_dict = space.newdict(instance=True)
- self.dicts.set(ec, 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
- self.dicts.set(ec, None)
- raise
- # ready
+ try:
+ w_dict = self.dicts[ec]
+ except KeyError:
+ w_dict = self.create_new_dict(ec)
return w_dict
def descr_local__new__(space, w_subtype, __args__):
@@ -55,3 +76,13 @@
__init__ = interp2app(Local.descr_local__init__),
__dict__ = GetSetProperty(descr_get_dict, cls=Local),
)
+
+def thread_is_stopping(ec):
+ tlobjs = ec._thread_local_objs
+ if tlobjs is None:
+ return
+ ec._thread_local_objs = None
+ for wref in tlobjs:
+ local = wref()
+ if local is not None:
+ del local.dicts[ec]
diff --git a/pypy/module/thread/threadlocals.py b/pypy/module/thread/threadlocals.py
--- a/pypy/module/thread/threadlocals.py
+++ b/pypy/module/thread/threadlocals.py
@@ -54,4 +54,8 @@
def leave_thread(self, space):
"Notification that the current thread is about to stop."
- self.setvalue(None)
+ from pypy.module.thread.os_local import thread_is_stopping
+ try:
+ thread_is_stopping(self.getvalue())
+ finally:
+ self.setvalue(None)
diff --git a/pypy/rlib/test/test_rweakkeydict.py b/pypy/rlib/test/test_rweakkeydict.py
--- a/pypy/rlib/test/test_rweakkeydict.py
+++ b/pypy/rlib/test/test_rweakkeydict.py
@@ -135,3 +135,32 @@
d = RWeakKeyDictionary(KX, VY)
d.set(KX(), VX())
py.test.raises(Exception, interpret, g, [1])
+
+
+def test_rpython_free_values():
+ import py; py.test.skip("XXX not implemented, messy")
+ class VXDel:
+ def __del__(self):
+ state.freed.append(1)
+ class State:
+ pass
+ state = State()
+ state.freed = []
+ #
+ def add_me():
+ k = KX()
+ v = VXDel()
+ d = RWeakKeyDictionary(KX, VXDel)
+ d.set(k, v)
+ return d
+ def f():
+ del state.freed[:]
+ d = add_me()
+ rgc.collect()
+ # we want the dictionary to be really empty here. It's hard to
+ # ensure in the current implementation after just one collect(),
+ # but at least two collects should be enough.
+ rgc.collect()
+ return len(state.freed)
+ assert f() == 1
+ assert interpret(f, []) == 1
More information about the pypy-commit
mailing list