mirror of https://github.com/python/cpython
gh-94777: Fix deadlock in ProcessPoolExecutor (#94784)
Fixes a hang in multiprocessing process pool executor when a child process crashes and code could otherwise block on writing to the pipe. See GH-94777 for more details.
This commit is contained in:
parent
9d582250d8
commit
6782fc0502
|
@ -499,6 +499,10 @@ class _ExecutorManagerThread(threading.Thread):
|
||||||
for p in self.processes.values():
|
for p in self.processes.values():
|
||||||
p.terminate()
|
p.terminate()
|
||||||
|
|
||||||
|
# Prevent queue writing to a pipe which is no longer read.
|
||||||
|
# https://github.com/python/cpython/issues/94777
|
||||||
|
self.call_queue._reader.close()
|
||||||
|
|
||||||
# clean up resources
|
# clean up resources
|
||||||
self.join_executor_internals()
|
self.join_executor_internals()
|
||||||
|
|
||||||
|
|
|
@ -1172,6 +1172,11 @@ def _crash(delay=None):
|
||||||
faulthandler._sigsegv()
|
faulthandler._sigsegv()
|
||||||
|
|
||||||
|
|
||||||
|
def _crash_with_data(data):
|
||||||
|
"""Induces a segfault with dummy data in input."""
|
||||||
|
_crash()
|
||||||
|
|
||||||
|
|
||||||
def _exit():
|
def _exit():
|
||||||
"""Induces a sys exit with exitcode 1."""
|
"""Induces a sys exit with exitcode 1."""
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
@ -1371,6 +1376,19 @@ class ExecutorDeadlockTest:
|
||||||
# dangling threads
|
# dangling threads
|
||||||
executor_manager.join()
|
executor_manager.join()
|
||||||
|
|
||||||
|
def test_crash_big_data(self):
|
||||||
|
# Test that there is a clean exception instad of a deadlock when a
|
||||||
|
# child process crashes while some data is being written into the
|
||||||
|
# queue.
|
||||||
|
# https://github.com/python/cpython/issues/94777
|
||||||
|
self.executor.shutdown(wait=True)
|
||||||
|
data = "a" * support.PIPE_MAX_SIZE
|
||||||
|
with self.executor_type(max_workers=2,
|
||||||
|
mp_context=self.get_context()) as executor:
|
||||||
|
self.executor = executor # Allow clean up in fail_on_deadlock
|
||||||
|
with self.assertRaises(BrokenProcessPool):
|
||||||
|
list(executor.map(_crash_with_data, [data] * 10))
|
||||||
|
|
||||||
|
|
||||||
create_executor_tests(ExecutorDeadlockTest,
|
create_executor_tests(ExecutorDeadlockTest,
|
||||||
executor_mixins=(ProcessPoolForkMixin,
|
executor_mixins=(ProcessPoolForkMixin,
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Fix hanging :mod:`multiprocessing` ``ProcessPoolExecutor`` when a child process crashes while data is being written in the call queue.
|
Loading…
Reference in New Issue