summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/multiprocessing/resource_tracker.py7
-rw-r--r--Lib/test/_test_multiprocessing.py21
-rw-r--r--Misc/NEWS.d/next/Library/2024-12-03-20-28-08.gh-issue-127586.zgotYF.rst3
3 files changed, 28 insertions, 3 deletions
diff --git a/Lib/multiprocessing/resource_tracker.py b/Lib/multiprocessing/resource_tracker.py
index 20ddd9c..90e036a 100644
--- a/Lib/multiprocessing/resource_tracker.py
+++ b/Lib/multiprocessing/resource_tracker.py
@@ -155,13 +155,14 @@ class ResourceTracker(object):
# that can make the child die before it registers signal handlers
# for SIGINT and SIGTERM. The mask is unregistered after spawning
# the child.
+ prev_sigmask = None
try:
if _HAVE_SIGMASK:
- signal.pthread_sigmask(signal.SIG_BLOCK, _IGNORED_SIGNALS)
+ prev_sigmask = signal.pthread_sigmask(signal.SIG_BLOCK, _IGNORED_SIGNALS)
pid = util.spawnv_passfds(exe, args, fds_to_pass)
finally:
- if _HAVE_SIGMASK:
- signal.pthread_sigmask(signal.SIG_UNBLOCK, _IGNORED_SIGNALS)
+ if prev_sigmask is not None:
+ signal.pthread_sigmask(signal.SIG_SETMASK, prev_sigmask)
except:
os.close(w)
raise
diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py
index 80b08b8..38a03f3 100644
--- a/Lib/test/_test_multiprocessing.py
+++ b/Lib/test/_test_multiprocessing.py
@@ -6045,6 +6045,27 @@ class TestResourceTracker(unittest.TestCase):
cleanup=cleanup,
)
+ @unittest.skipUnless(hasattr(signal, "pthread_sigmask"), "pthread_sigmask is not available")
+ def test_resource_tracker_blocked_signals(self):
+ #
+ # gh-127586: Check that resource_tracker does not override blocked signals of caller.
+ #
+ from multiprocessing.resource_tracker import ResourceTracker
+ orig_sigmask = signal.pthread_sigmask(signal.SIG_BLOCK, set())
+ signals = {signal.SIGTERM, signal.SIGINT, signal.SIGUSR1}
+
+ try:
+ for sig in signals:
+ signal.pthread_sigmask(signal.SIG_SETMASK, {sig})
+ self.assertEqual(signal.pthread_sigmask(signal.SIG_BLOCK, set()), {sig})
+ tracker = ResourceTracker()
+ tracker.ensure_running()
+ self.assertEqual(signal.pthread_sigmask(signal.SIG_BLOCK, set()), {sig})
+ tracker._stop()
+ finally:
+ # restore sigmask to what it was before executing test
+ signal.pthread_sigmask(signal.SIG_SETMASK, orig_sigmask)
+
class TestSimpleQueue(unittest.TestCase):
@classmethod
diff --git a/Misc/NEWS.d/next/Library/2024-12-03-20-28-08.gh-issue-127586.zgotYF.rst b/Misc/NEWS.d/next/Library/2024-12-03-20-28-08.gh-issue-127586.zgotYF.rst
new file mode 100644
index 0000000..80217bd
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-12-03-20-28-08.gh-issue-127586.zgotYF.rst
@@ -0,0 +1,3 @@
+:class:`multiprocessing.pool.Pool` now properly restores blocked signal handlers
+of the parent thread when creating processes via either *spawn* or
+*forkserver*.