summaryrefslogtreecommitdiffstats
path: root/Lib/multiprocessing
diff options
context:
space:
mode:
authorThomas Moreau <thomas.moreau.2010@gmail.com>2019-04-24 19:45:52 (GMT)
committerAntoine Pitrou <antoine@python.org>2019-04-24 19:45:52 (GMT)
commit004b93ea8947bcbe85b6fa16fe0999bfa712d5c1 (patch)
treef878d3c76b355822e4f88bc92f55a6511bd9dd4f /Lib/multiprocessing
parent09d434caa2c01477ea2ccc3e9b88e9faa0107c61 (diff)
downloadcpython-004b93ea8947bcbe85b6fa16fe0999bfa712d5c1.zip
cpython-004b93ea8947bcbe85b6fa16fe0999bfa712d5c1.tar.gz
cpython-004b93ea8947bcbe85b6fa16fe0999bfa712d5c1.tar.bz2
bpo-36668: FIX reuse semaphore tracker for child processes (#5172)
Fix the multiprocessing.semaphore_tracker so it is reused by child processes.
Diffstat (limited to 'Lib/multiprocessing')
-rw-r--r--Lib/multiprocessing/semaphore_tracker.py36
1 files changed, 26 insertions, 10 deletions
diff --git a/Lib/multiprocessing/semaphore_tracker.py b/Lib/multiprocessing/semaphore_tracker.py
index 82833bc..3c2c3ad 100644
--- a/Lib/multiprocessing/semaphore_tracker.py
+++ b/Lib/multiprocessing/semaphore_tracker.py
@@ -44,20 +44,23 @@ class SemaphoreTracker(object):
This can be run from any process. Usually a child process will use
the semaphore created by its parent.'''
with self._lock:
- if self._pid is not None:
+ if self._fd is not None:
# semaphore tracker was launched before, is it still running?
+ if self._check_alive():
+ # => still alive
+ return
+ # => dead, launch it again
+ os.close(self._fd)
+
+ # Clean-up to avoid dangling processes.
try:
- pid, _ = os.waitpid(self._pid, os.WNOHANG)
+ # _pid can be None if this process is a child from another
+ # python process, which has started the semaphore_tracker.
+ if self._pid is not None:
+ os.waitpid(self._pid, 0)
except ChildProcessError:
- # The process terminated
+ # The semaphore_tracker has already been terminated.
pass
- else:
- if not pid:
- # => still alive
- return
-
- # => dead, launch it again
- os.close(self._fd)
self._fd = None
self._pid = None
@@ -99,6 +102,17 @@ class SemaphoreTracker(object):
finally:
os.close(r)
+ def _check_alive(self):
+ '''Check that the pipe has not been closed by sending a probe.'''
+ try:
+ # We cannot use send here as it calls ensure_running, creating
+ # a cycle.
+ os.write(self._fd, b'PROBE:0\n')
+ except OSError:
+ return False
+ else:
+ return True
+
def register(self, name):
'''Register name of semaphore with semaphore tracker.'''
self._send('REGISTER', name)
@@ -150,6 +164,8 @@ def main(fd):
cache.add(name)
elif cmd == b'UNREGISTER':
cache.remove(name)
+ elif cmd == b'PROBE':
+ pass
else:
raise RuntimeError('unrecognized command %r' % cmd)
except Exception: