From b087268217703887c08d580c888813162634353f Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Mon, 9 Nov 2009 16:08:16 +0000 Subject: [PATCH] Merged revisions 76172 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r76172 | antoine.pitrou | 2009-11-09 17:00:11 +0100 (lun., 09 nov. 2009) | 5 lines Issue #7282: Fix a memory leak when an RLock was used in a thread other than those started through `threading.Thread` (for example, using `thread.start_new_thread()`. ........ --- Lib/test/lock_tests.py | 13 +++++++++++++ Lib/test/test_threading.py | 6 ++---- Lib/threading.py | 18 ++++++++++-------- Misc/NEWS | 4 ++++ 4 files changed, 29 insertions(+), 12 deletions(-) diff --git a/Lib/test/lock_tests.py b/Lib/test/lock_tests.py index f9c2259914c..04f7422c8de 100644 --- a/Lib/test/lock_tests.py +++ b/Lib/test/lock_tests.py @@ -130,6 +130,19 @@ class BaseLockTests(BaseTestCase): # Check the lock is unacquired Bunch(f, 1).wait_for_finished() + def test_thread_leak(self): + # The lock shouldn't leak a Thread instance when used from a foreign + # (non-threading) thread. + lock = self.locktype() + def f(): + lock.acquire() + lock.release() + n = len(threading.enumerate()) + # We run many threads in the hope that existing threads ids won't + # be recycled. + Bunch(f, 15).wait_for_finished() + self.assertEqual(n, len(threading.enumerate())) + class LockTests(BaseLockTests): """ diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index 5e18243743f..41f57dc3120 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -143,11 +143,9 @@ class ThreadTests(BaseTestCase): def test_foreign_thread(self): # Check that a "foreign" thread can use the threading module. def f(mutex): - # Acquiring an RLock forces an entry for the foreign + # Calling current_thread() forces an entry for the foreign # thread to get made in the threading._active map. - r = threading.RLock() - r.acquire() - r.release() + threading.current_thread() mutex.release() mutex = threading.Lock() diff --git a/Lib/threading.py b/Lib/threading.py index d5412e935c7..4bb0182e66f 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -92,14 +92,16 @@ class _RLock(_Verbose): def __repr__(self): owner = self._owner - return "<%s(%s, %d)>" % ( - self.__class__.__name__, - owner and owner.name, - self._count) + try: + owner = _active[owner].name + except KeyError: + pass + return "<%s owner=%r count=%d>" % ( + self.__class__.__name__, owner, self._count) def acquire(self, blocking=True): - me = current_thread() - if self._owner is me: + me = _get_ident() + if self._owner == me: self._count = self._count + 1 if __debug__: self._note("%s.acquire(%s): recursive success", self, blocking) @@ -118,7 +120,7 @@ class _RLock(_Verbose): __enter__ = acquire def release(self): - if self._owner is not current_thread(): + if self._owner != _get_ident(): raise RuntimeError("cannot release un-acquired lock") self._count = count = self._count - 1 if not count: @@ -152,7 +154,7 @@ class _RLock(_Verbose): return (count, owner) def _is_owned(self): - return self._owner is current_thread() + return self._owner == _get_ident() def Condition(*args, **kwargs): diff --git a/Misc/NEWS b/Misc/NEWS index 94c16bb900b..8c0f0ecbd1f 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -123,6 +123,10 @@ C-API Library ------- +- Issue #7282: Fix a memory leak when an RLock was used in a thread other + than those started through `threading.Thread` (for example, using + `_thread.start_new_thread()`). + - Issue #7187: Importlib would not silence the IOError raised when trying to write new bytecode when it was made read-only.