Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r54995:f86cddbfc751 Date: 2012-05-09 21:21 +0200 http://bitbucket.org/pypy/pypy/changeset/f86cddbfc751/
Log: Tweak again thread._local. Cannot use RWeakKeyDictionary in its current implementation, because of the warning in rlib._rweakkeydict:13. It would mean that the __dict__ of some long-dead threads might remain around for an unknown amount of time. 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,19 @@ -from pypy.rlib.rweakref import RWeakKeyDictionary +import weakref 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""" 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,15 +21,24 @@ # 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)) def getdict(self, space): ec = space.getexecutioncontext() - w_dict = self.dicts.get(ec) - if w_dict is None: + try: + w_dict = self.dicts[ec] + except KeyError: # create a new dict for this thread w_dict = space.newdict(instance=True) - self.dicts.set(ec, w_dict) + self.dicts[ec] = w_dict # call __init__ try: w_self = space.wrap(self) @@ -35,9 +47,10 @@ space.call_obj_args(w_init, w_self, self.initargs) except: # failed, forget w_dict and propagate the exception - self.dicts.set(ec, None) + del self.dicts[ec] raise # ready + self._register_in_ec(ec) return w_dict def descr_local__new__(space, w_subtype, __args__): @@ -55,3 +68,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) _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit