diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2013-09-08 11:19:06 (GMT) |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2013-09-08 11:19:06 (GMT) |
commit | 5da7e7959e6d3032a564eea68746e03764ed2f68 (patch) | |
tree | af901dac5b86423cde3d47e6a662fe113d19720c | |
parent | 6f6f4865d138f2348889ccc08aa8b18ca0263e48 (diff) | |
download | cpython-5da7e7959e6d3032a564eea68746e03764ed2f68.zip cpython-5da7e7959e6d3032a564eea68746e03764ed2f68.tar.gz cpython-5da7e7959e6d3032a564eea68746e03764ed2f68.tar.bz2 |
Issue #18808 again: fix the after-fork logic for not-yet-started or already-stopped threads.
(AFAICT, in theory, we must reset all the locks, not just those in use)
-rw-r--r-- | Lib/test/test_threading.py | 2 | ||||
-rw-r--r-- | Lib/threading.py | 16 |
2 files changed, 8 insertions, 10 deletions
diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index 79b10ed..58b0b4e 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -109,7 +109,7 @@ class ThreadTests(BaseTestCase): if verbose: print('waiting for all tasks to complete') for t in threads: - t.join(NUMTASKS) + t.join() self.assertTrue(not t.is_alive()) self.assertNotEqual(t.ident, 0) self.assertFalse(t.ident is None) diff --git a/Lib/threading.py b/Lib/threading.py index 4d3c6f6..b4b73a8 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -517,8 +517,6 @@ def _newname(template="Thread-%d"): _active_limbo_lock = _allocate_lock() _active = {} # maps thread id to Thread object _limbo = {} - -# For debug and leak testing _dangling = WeakSet() # Main class for threads @@ -552,14 +550,11 @@ class Thread: self._tstate_lock = None self._started = Event() self._stopped = Event() - # _is_stopped should be the same as _stopped.is_set(). The bizarre - # duplication is to allow test_is_alive_after_fork to pass on old - # Linux kernels. See issue 18808. - self._is_stopped = False self._initialized = True # sys.stderr is not stored in the class like # sys.exc_info since it can be changed between instances self._stderr = _sys.stderr + # For debugging and _after_fork() _dangling.add(self) def _reset_internal_locks(self, is_alive): @@ -711,7 +706,6 @@ class Thread: def _stop(self): self._stopped.set() - self._is_stopped = True def _delete(self): "Remove current thread from the dict of currently running threads." @@ -798,7 +792,7 @@ class Thread: assert self._initialized, "Thread.__init__() not called" if not self._started.is_set(): return False - if not self._is_stopped: + if not self._stopped.is_set(): return True # The Python part of the thread is done, but the C part may still be # waiting to run. @@ -976,7 +970,11 @@ def _after_fork(): current = current_thread() _main_thread = current with _active_limbo_lock: - for thread in _enumerate(): + # Dangling thread instances must still have their locks reset, + # because someone may join() them. + threads = set(_enumerate()) + threads.update(_dangling) + for thread in threads: # Any lock/condition variable may be currently locked or in an # invalid state, so we reinitialize them. if thread is current: |