]> granicus.if.org Git - python/commitdiff
Kill a race in test_threading in which the exception info in a thread finishing
authorJeffrey Yasskin <jyasskin@gmail.com>
Fri, 28 Mar 2008 04:11:18 +0000 (04:11 +0000)
committerJeffrey Yasskin <jyasskin@gmail.com>
Fri, 28 Mar 2008 04:11:18 +0000 (04:11 +0000)
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.

Lib/test/test_threading.py
Lib/threading.py

index e309a5439e4f12eccd9d0e25148d6ee9c8546457..195c4e8f73344a52cdac22722c391aaf6f2fd060 100644 (file)
@@ -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):
index 86153b0f5c1f4437bf778116d7207ce02fa99807..eebe10a9c0f95db3869ba7dc781d81627ef12cf8 100644 (file)
@@ -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()