]> granicus.if.org Git - python/commitdiff
#1733757: the interpreter would hang on shutdown, if the function set by sys.settrace
authorAmaury Forgeot d'Arc <amauryfa@gmail.com>
Thu, 3 Apr 2008 23:07:55 +0000 (23:07 +0000)
committerAmaury Forgeot d'Arc <amauryfa@gmail.com>
Thu, 3 Apr 2008 23:07:55 +0000 (23:07 +0000)
calls threading.currentThread.

The correction somewhat improves the code, but it was close.
Many thanks to the "with" construct, which turns python code into C calls.

I wonder if it is not better to sys.settrace(None) just after
running the __main__ module and before finalization.

Lib/test/test_threading.py
Lib/threading.py
Misc/NEWS

index 195c4e8f73344a52cdac22722c391aaf6f2fd060..30aa9d578675a6636b6b1265259c59f215cda2ab 100644 (file)
@@ -238,6 +238,35 @@ class ThreadTests(unittest.TestCase):
             """])
         self.assertEqual(rc, 42)
 
+    def test_finalize_with_trace(self):
+        # Issue1733757
+        # Avoid a deadlock when sys.settrace steps into threading._shutdown
+        import subprocess
+        rc = subprocess.call([sys.executable, "-c", """if 1:
+            import sys, threading
+
+            # A deadlock-killer, to prevent the
+            # testsuite to hang forever
+            def killer():
+                import os, time
+                time.sleep(2)
+                print 'program blocked; aborting'
+                os._exit(2)
+            t = threading.Thread(target=killer)
+            t.setDaemon(True)
+            t.start()
+
+            # This is the trace function
+            def func(frame, event, arg):
+                threading.currentThread()
+                return func
+
+            sys.settrace(func)
+            """])
+        self.failIf(rc == 2, "interpreted was blocked")
+        self.failUnless(rc == 0, "Unexpected error")
+
+
     def test_enumerate_after_join(self):
         # Try hard to trigger #1703448: a thread is still returned in
         # threading.enumerate() after it has been join()ed.
index 516e22ded7d3121a54c98afe9dcc4b24a6f28b5d..d497a46dc7b8773f6e387a1a05f43244e9d996ae 100644 (file)
@@ -583,15 +583,16 @@ class Thread(_Verbose):
         # since it isn't if dummy_threading is *not* being used then don't
         # hide the exception.
 
-        _active_limbo_lock.acquire()
         try:
-            try:
+            with _active_limbo_lock:
                 del _active[_get_ident()]
-            except KeyError:
-                if 'dummy_threading' not in _sys.modules:
-                    raise
-        finally:
-            _active_limbo_lock.release()
+                # There must not be any python code between the previous line
+                # and after the lock is released.  Otherwise a tracing function
+                # could try to acquire the lock again in the same thread, (in
+                # currentThread()), and would block.
+        except KeyError:
+            if 'dummy_threading' not in _sys.modules:
+                raise
 
     def join(self, timeout=None):
         if not self.__initialized:
index e9e736c031542642a4443a9efa3417818d746aeb..945afdf25daf66aeda9501ad5e23a484722bdc0c 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,10 @@ What's New in Python 2.6 alpha 2?
 Core and builtins
 -----------------
 
+- Issue #1733757: The interpreter would hang on shutdown if the tracing 
+  function set by sys.settrace is still active and happens to call
+  threading.currentThread().
+
 - Patch #1442: properly report exceptions when the PYTHONSTARTUP file
   cannot be executed.