[Python-checkins] r62136 - in python/trunk: Lib/test/test_threading.py Lib/threading.py Misc/NEWS

amaury.forgeotdarc python-checkins at python.org
Fri Apr 4 01:07:55 CEST 2008


Author: amaury.forgeotdarc
Date: Fri Apr  4 01:07:55 2008
New Revision: 62136

Modified:
   python/trunk/Lib/test/test_threading.py
   python/trunk/Lib/threading.py
   python/trunk/Misc/NEWS
Log:
#1733757: the interpreter would hang on shutdown, if the function set by sys.settrace
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.


Modified: python/trunk/Lib/test/test_threading.py
==============================================================================
--- python/trunk/Lib/test/test_threading.py	(original)
+++ python/trunk/Lib/test/test_threading.py	Fri Apr  4 01:07:55 2008
@@ -238,6 +238,35 @@
             """])
         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.

Modified: python/trunk/Lib/threading.py
==============================================================================
--- python/trunk/Lib/threading.py	(original)
+++ python/trunk/Lib/threading.py	Fri Apr  4 01:07:55 2008
@@ -583,15 +583,16 @@
         # 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:

Modified: python/trunk/Misc/NEWS
==============================================================================
--- python/trunk/Misc/NEWS	(original)
+++ python/trunk/Misc/NEWS	Fri Apr  4 01:07:55 2008
@@ -12,6 +12,10 @@
 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.
 


More information about the Python-checkins mailing list