summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2023-09-06 13:57:01 (GMT)
committerGitHub <noreply@github.com>2023-09-06 13:57:01 (GMT)
commita8cae4071c795e55be46e339eda37e241fa0d7f8 (patch)
treea91d0b46c6492d7fb090a1d5430acd95db27f979
parentb298b395e8ab1725c4f0dd736155b8c818664d42 (diff)
downloadcpython-a8cae4071c795e55be46e339eda37e241fa0d7f8.zip
cpython-a8cae4071c795e55be46e339eda37e241fa0d7f8.tar.gz
cpython-a8cae4071c795e55be46e339eda37e241fa0d7f8.tar.bz2
gh-107219: Fix concurrent.futures terminate_broken() (#108974)
Fix a race condition in _ExecutorManagerThread.terminate_broken(): ignore the InvalidStateError on future.set_exception(). It can happen if the future is cancelled before the caller. Moreover, test_crash_big_data() now waits explicitly until the executor completes.
-rw-r--r--Lib/concurrent/futures/process.py9
-rw-r--r--Lib/test/test_concurrent_futures/test_deadlock.py2
2 files changed, 10 insertions, 1 deletions
diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py
index 301207f..9933d3d 100644
--- a/Lib/concurrent/futures/process.py
+++ b/Lib/concurrent/futures/process.py
@@ -489,7 +489,14 @@ class _ExecutorManagerThread(threading.Thread):
# Mark pending tasks as failed.
for work_id, work_item in self.pending_work_items.items():
- work_item.future.set_exception(bpe)
+ try:
+ work_item.future.set_exception(bpe)
+ except _base.InvalidStateError as exc:
+ # set_exception() fails if the future is cancelled: ignore it.
+ # Trying to check if the future is cancelled before calling
+ # set_exception() would leave a race condition if the future is
+ # cancelled betwen the check and set_exception().
+ pass
# Delete references to object. See issue16284
del work_item
self.pending_work_items.clear()
diff --git a/Lib/test/test_concurrent_futures/test_deadlock.py b/Lib/test/test_concurrent_futures/test_deadlock.py
index 6b78b36..baac2b5 100644
--- a/Lib/test/test_concurrent_futures/test_deadlock.py
+++ b/Lib/test/test_concurrent_futures/test_deadlock.py
@@ -239,6 +239,8 @@ class ExecutorDeadlockTest:
with self.assertRaises(BrokenProcessPool):
list(executor.map(_crash_with_data, [data] * 10))
+ executor.shutdown(wait=True)
+
create_executor_tests(globals(), ExecutorDeadlockTest,
executor_mixins=(ProcessPoolForkMixin,