summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeffrey Yasskin <jyasskin@gmail.com>2008-03-28 04:11:18 (GMT)
committerJeffrey Yasskin <jyasskin@gmail.com>2008-03-28 04:11:18 (GMT)
commit8b9091fba07b813b7486ef8fef279f2bf950570b (patch)
tree7dd25f52ebbe7c8276901a03bad5d651e693845c
parent7db15fe9d9f42b73b8dad4d13965259de2eea09f (diff)
downloadcpython-8b9091fba07b813b7486ef8fef279f2bf950570b.zip
cpython-8b9091fba07b813b7486ef8fef279f2bf950570b.tar.gz
cpython-8b9091fba07b813b7486ef8fef279f2bf950570b.tar.bz2
Kill a race in test_threading in which the exception info in a thread finishing
up after it was joined had a traceback pointing to that thread's (deleted) target attribute, while the test was trying to check that the target was destroyed. Big thanks to Antoine Pitrou for diagnosing the race and pointing out sys.exc_clear() to kill the exception early. This fixes issue 2496.
-rw-r--r--Lib/test/test_threading.py8
-rw-r--r--Lib/threading.py9
2 files changed, 15 insertions, 2 deletions
diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py
index e309a54..195c4e8 100644
--- a/Lib/test/test_threading.py
+++ b/Lib/test/test_threading.py
@@ -276,13 +276,17 @@ class ThreadTests(unittest.TestCase):
weak_cyclic_object = weakref.ref(cyclic_object)
cyclic_object.thread.join()
del cyclic_object
- self.assertEquals(None, weak_cyclic_object())
+ self.assertEquals(None, weak_cyclic_object(),
+ msg=('%d references still around' %
+ sys.getrefcount(weak_cyclic_object())))
raising_cyclic_object = RunSelfFunction(should_raise=True)
weak_raising_cyclic_object = weakref.ref(raising_cyclic_object)
raising_cyclic_object.thread.join()
del raising_cyclic_object
- self.assertEquals(None, weak_raising_cyclic_object())
+ self.assertEquals(None, weak_raising_cyclic_object(),
+ msg=('%d references still around' %
+ sys.getrefcount(weak_raising_cyclic_object())))
class ThreadingExceptionTests(unittest.TestCase):
diff --git a/Lib/threading.py b/Lib/threading.py
index 86153b0..eebe10a 100644
--- a/Lib/threading.py
+++ b/Lib/threading.py
@@ -392,6 +392,9 @@ class Thread(_Verbose):
# shutdown and thus raises an exception about trying to perform some
# operation on/with a NoneType
__exc_info = _sys.exc_info
+ # Keep sys.exc_clear too to clear the exception just before
+ # allowing .join() to return.
+ __exc_clear = _sys.exc_clear
def __init__(self, group=None, target=None, name=None,
args=(), kwargs=None, verbose=None):
@@ -527,6 +530,12 @@ class Thread(_Verbose):
else:
if __debug__:
self._note("%s.__bootstrap(): normal return", self)
+ finally:
+ # Prevent a race in
+ # test_threading.test_no_refcycle_through_target when
+ # the exception keeps the target alive past when we
+ # assert that it's dead.
+ self.__exc_clear()
finally:
with _active_limbo_lock:
self.__stop()