summaryrefslogtreecommitdiffstats
path: root/Lib/test/_test_multiprocessing.py
diff options
context:
space:
mode:
authorPablo Galindo <Pablogsal@gmail.com>2018-09-04 08:53:54 (GMT)
committerAntoine Pitrou <pitrou@free.fr>2018-09-04 08:53:54 (GMT)
commitec74d187f50a8a48f94eb37023300583fbd644cc (patch)
tree718f782542818ce6062448a35f99388511fb1e56 /Lib/test/_test_multiprocessing.py
parente9ba3705de656215d52b8f8f4a2e7ad60190e944 (diff)
downloadcpython-ec74d187f50a8a48f94eb37023300583fbd644cc.zip
cpython-ec74d187f50a8a48f94eb37023300583fbd644cc.tar.gz
cpython-ec74d187f50a8a48f94eb37023300583fbd644cc.tar.bz2
bpo-33613, test_semaphore_tracker_sigint: fix race condition (#7850)
Fail `test_semaphore_tracker_sigint` if no warnings are expected and one is received. Fix race condition when the child receives SIGINT before it can register signal handlers for it. The race condition occurs when the parent calls `_semaphore_tracker.ensure_running()` (which in turn spawns the semaphore_tracker using `_posixsubprocess.fork_exec`), the child registers the signal handlers and the parent tries to kill the child. What seem to happen is that in some slow systems, the parent sends the signal to kill the child before the child protects against the signal.
Diffstat (limited to 'Lib/test/_test_multiprocessing.py')
-rw-r--r--Lib/test/_test_multiprocessing.py27
1 files changed, 21 insertions, 6 deletions
diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py
index 749cf8c..a5509ce 100644
--- a/Lib/test/_test_multiprocessing.py
+++ b/Lib/test/_test_multiprocessing.py
@@ -20,6 +20,7 @@ import logging
import struct
import operator
import weakref
+import warnings
import test.support
import test.support.script_helper
from test import support
@@ -4517,17 +4518,19 @@ class TestSemaphoreTracker(unittest.TestCase):
# bpo-31310: if the semaphore tracker process has died, it should
# be restarted implicitly.
from multiprocessing.semaphore_tracker import _semaphore_tracker
- _semaphore_tracker.ensure_running()
pid = _semaphore_tracker._pid
+ if pid is not None:
+ os.kill(pid, signal.SIGKILL)
+ os.waitpid(pid, 0)
+ with warnings.catch_warnings(record=True) as all_warn:
+ _semaphore_tracker.ensure_running()
+ pid = _semaphore_tracker._pid
+
os.kill(pid, signum)
time.sleep(1.0) # give it time to die
ctx = multiprocessing.get_context("spawn")
- with contextlib.ExitStack() as stack:
- if should_die:
- stack.enter_context(self.assertWarnsRegex(
- UserWarning,
- "semaphore_tracker: process died"))
+ with warnings.catch_warnings(record=True) as all_warn:
sem = ctx.Semaphore()
sem.acquire()
sem.release()
@@ -4537,11 +4540,23 @@ class TestSemaphoreTracker(unittest.TestCase):
del sem
gc.collect()
self.assertIsNone(wr())
+ if should_die:
+ self.assertEqual(len(all_warn), 1)
+ the_warn = all_warn[0]
+ issubclass(the_warn.category, UserWarning)
+ self.assertTrue("semaphore_tracker: process died"
+ in str(the_warn.message))
+ else:
+ self.assertEqual(len(all_warn), 0)
def test_semaphore_tracker_sigint(self):
# Catchable signal (ignored by semaphore tracker)
self.check_semaphore_tracker_death(signal.SIGINT, False)
+ def test_semaphore_tracker_sigterm(self):
+ # Catchable signal (ignored by semaphore tracker)
+ self.check_semaphore_tracker_death(signal.SIGTERM, False)
+
def test_semaphore_tracker_sigkill(self):
# Uncatchable signal.
self.check_semaphore_tracker_death(signal.SIGKILL, True)