mirror of
https://github.com/python/cpython.git
synced 2025-07-29 06:05:00 +00:00
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()`.
This commit is contained in:
parent
d19915ed76
commit
d7158d4c62
4 changed files with 29 additions and 12 deletions
|
@ -130,6 +130,19 @@ class BaseLockTests(BaseTestCase):
|
||||||
# Check the lock is unacquired
|
# Check the lock is unacquired
|
||||||
Bunch(f, 1).wait_for_finished()
|
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):
|
class LockTests(BaseLockTests):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -143,11 +143,9 @@ class ThreadTests(BaseTestCase):
|
||||||
def test_foreign_thread(self):
|
def test_foreign_thread(self):
|
||||||
# Check that a "foreign" thread can use the threading module.
|
# Check that a "foreign" thread can use the threading module.
|
||||||
def f(mutex):
|
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.
|
# thread to get made in the threading._active map.
|
||||||
r = threading.RLock()
|
threading.current_thread()
|
||||||
r.acquire()
|
|
||||||
r.release()
|
|
||||||
mutex.release()
|
mutex.release()
|
||||||
|
|
||||||
mutex = threading.Lock()
|
mutex = threading.Lock()
|
||||||
|
|
|
@ -106,14 +106,16 @@ class _RLock(_Verbose):
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
owner = self.__owner
|
owner = self.__owner
|
||||||
return "<%s(%s, %d)>" % (
|
try:
|
||||||
self.__class__.__name__,
|
owner = _active[owner].name
|
||||||
owner and owner.name,
|
except KeyError:
|
||||||
self.__count)
|
pass
|
||||||
|
return "<%s owner=%r count=%d>" % (
|
||||||
|
self.__class__.__name__, owner, self.__count)
|
||||||
|
|
||||||
def acquire(self, blocking=1):
|
def acquire(self, blocking=1):
|
||||||
me = current_thread()
|
me = _get_ident()
|
||||||
if self.__owner is me:
|
if self.__owner == me:
|
||||||
self.__count = self.__count + 1
|
self.__count = self.__count + 1
|
||||||
if __debug__:
|
if __debug__:
|
||||||
self._note("%s.acquire(%s): recursive success", self, blocking)
|
self._note("%s.acquire(%s): recursive success", self, blocking)
|
||||||
|
@ -132,7 +134,7 @@ class _RLock(_Verbose):
|
||||||
__enter__ = acquire
|
__enter__ = acquire
|
||||||
|
|
||||||
def release(self):
|
def release(self):
|
||||||
if self.__owner is not current_thread():
|
if self.__owner != _get_ident():
|
||||||
raise RuntimeError("cannot release un-acquired lock")
|
raise RuntimeError("cannot release un-acquired lock")
|
||||||
self.__count = count = self.__count - 1
|
self.__count = count = self.__count - 1
|
||||||
if not count:
|
if not count:
|
||||||
|
@ -168,7 +170,7 @@ class _RLock(_Verbose):
|
||||||
return (count, owner)
|
return (count, owner)
|
||||||
|
|
||||||
def _is_owned(self):
|
def _is_owned(self):
|
||||||
return self.__owner is current_thread()
|
return self.__owner == _get_ident()
|
||||||
|
|
||||||
|
|
||||||
def Condition(*args, **kwargs):
|
def Condition(*args, **kwargs):
|
||||||
|
|
|
@ -426,6 +426,10 @@ Core and Builtins
|
||||||
Library
|
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 #7264: Fix a possible deadlock when deallocating thread-local objects
|
- Issue #7264: Fix a possible deadlock when deallocating thread-local objects
|
||||||
which are part of a reference cycle.
|
which are part of a reference cycle.
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue