-
-
Notifications
You must be signed in to change notification settings - Fork 30.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
test_multiprocessing_fork: test_semaphore_tracker_sigint() fails with -W error #77794
Comments
test_semaphore_tracker_sigint() emits a warning. If the test is run with -W error, the test fails. vstinner@apu$ ./python -m test test_multiprocessing_fork -v -m test_semaphore_tracker_sigint vstinner@apu$ ./python -Werror -m test test_multiprocessing_fork -v -m test_semaphore_tracker_sigint Traceback (most recent call last):
File "/home/vstinner/prog/python/master/Lib/test/_test_multiprocessing.py", line 4533, in test_semaphore_tracker_sigint
self.check_semaphore_tracker_death(signal.SIGINT, False)
File "/home/vstinner/prog/python/master/Lib/test/_test_multiprocessing.py", line 4521, in check_semaphore_tracker_death
sem = ctx.Semaphore()
File "/home/vstinner/prog/python/master/Lib/multiprocessing/context.py", line 82, in Semaphore
return Semaphore(value, ctx=self.get_context())
File "/home/vstinner/prog/python/master/Lib/multiprocessing/synchronize.py", line 127, in __init__
SemLock.__init__(self, SEMAPHORE, value, SEM_VALUE_MAX, ctx=ctx)
File "/home/vstinner/prog/python/master/Lib/multiprocessing/synchronize.py", line 81, in __init__
register(self._semlock.name)
File "/home/vstinner/prog/python/master/Lib/multiprocessing/semaphore_tracker.py", line 83, in register
self._send('REGISTER', name)
File "/home/vstinner/prog/python/master/Lib/multiprocessing/semaphore_tracker.py", line 90, in _send
self.ensure_running()
File "/home/vstinner/prog/python/master/Lib/multiprocessing/semaphore_tracker.py", line 55, in ensure_running
warnings.warn('semaphore_tracker: process died unexpectedly, '
UserWarning: semaphore_tracker: process died unexpectedly, relaunching. Some semaphores might leak.
(...)
Tests result: FAILURE |
Note: I found this bug while working on bpo-33612. |
(Oops, I attached a file and added two comments to this issue, whereas I wanted to comment bpo-33612.) |
See also some information about this in bpo-31463. |
I would like to work on this issue and on bpo-31463 |
Say it on bpo-31463 as well on that case ;-) |
There are two problems in test_semaphore_tracker_sigint. One of the problems is that if _semaphore_tracker.ensure_running()
pid = _semaphore_tracker._pid
os.kill(pid, signum)
time.sleep(1.0) # give it time to die to _semaphore_tracker.ensure_running()
pid = _semaphore_tracker._pid
time.sleep(1.0) # Give time for the child to register the signal handlers
os.kill(pid, signum)
time.sleep(1.0) # give it time to die fix the issue. I have tested this on one of the most grumpy and slow buildbots (gcc110) and it works. I cannot think of a different way of waiting for the child to register the signals without modifying the child code for testing so I am not sure that we can do anything rather than the sleep. |
You can know that the semaphore tracker is running by sending it an invalid command and seeing the error written to stderr. The semaphore tracker either inherits sys.stderr from the parent process (if possible) or uses its own. This is a bit of a hack, but might be worth it to avoid another wasted second on every run of the test suite. |
@taleinat Sadly, if the semaphore_tracker receives an invalid command, it raises and dies, making the test impossible:
|
We can easily add a 'NOOP' command to the semaphore tracker if it helps solve that issue. |
Sorry, I was wrong, it does not die. I am investigating this solution using stderr. |
Additionally, as I commented in the PR, apart from the race condition I think the test should be modified so it fails if the warning is raised and not expected:
|
@pitrou I think that should be ideal. The reason is that if we send an invalid command the cache is not cleared and the semaphore tracker will warn when the process finishes which is precisely what the test is avoiding. |
For the "no-op" we'll need a way to know that it was processed. To that end, I'd make the semaphore tracker recognize a new command e.g. "PING", upon which it would write something e.g. "PONG" into its end of the pipe. |
I have updated the PR implementing a PONG command in the semaphore and updating the test. I have tested on the failing buildbots (gcc110.fsffrance.org) and it works. Notice that a new pipe for the child to write was needed as the child is continuously reading from the original one and therefore we cannot use the same one. |
Is it possible to notify the ping / noop reply on stderr instead of introducing a new pipe? |
The process seems to use its own stderr and it cannot be captured from the parent without modifying it AFAIK. |
I have modified the PR to avoid creating an extra pipe in the tracker (the pipe is created as part of the test). To allow testing with the -R option: ./python -m test test_multiprocessing_fork -v -m test_semaphore_tracker_sigint -R 3:3 I had to assure that we restart the tracker in the test so it does not reuse a closed file descriptor. |
See also bpo-31687. |
IMHO the fix should be backported to Python 3.6 and 3.7. It cannot be backported to 2.7 since 2.7 doesn't have signal.pthread_sigmask(). |
As I wrote on Github: no user-visible bug is fixed here, and we shouldn't risk introducing regressions by backporting those changes. If buildbots hurt, I suggest skipping the tests on the buildbots. |
Let's do that. Pablo: do you want to write a PR to always skip TestSemaphoreTracker with a reference to this issue? Example: skipIf(True, "bpo-33613: the test has a race condition"). |
Please only skip those tests on buildbots. They work fine otherwise. |
There is no easy wait to only skip a test on buildbots.
The race condition impacts everyone. It's just less likely if your computer is fast enough. The bug is much more likely if you "force" the bad path: diff --git a/Lib/multiprocessing/semaphore_tracker.py b/Lib/multiprocessing/semaphore_tracker.py
index 3b50a46ddc..7261b43725 100644
--- a/Lib/multiprocessing/semaphore_tracker.py
+++ b/Lib/multiprocessing/semaphore_tracker.py
@@ -107,6 +107,8 @@ getfd = _semaphore_tracker.getfd
def main(fd):
'''Run semaphore tracker.'''
# protect the process from ^C and "killall python" etc
+ import time
+ time.sleep(0.5)
signal.signal(signal.SIGINT, signal.SIG_IGN)
signal.signal(signal.SIGTERM, signal.SIG_IGN)
diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py
index 5c625dd495..6f9f7583e2 100644
--- a/Lib/test/_test_multiprocessing.py
+++ b/Lib/test/_test_multiprocessing.py
@@ -4193,7 +4193,6 @@ class TestSemaphoreTracker(unittest.TestCase):
_multiprocessing.sem_unlink(name1)
p.terminate()
p.wait()
- time.sleep(2.0)
with self.assertRaises(OSError) as ctx:
_multiprocessing.sem_unlink(name2)
# docs say it should be ENOENT, but OSX seems to give EINVAL |
Le 04/09/2018 à 11:16, STINNER Victor a écrit :
Which bug? It's only a failing test. |
By the way, "no user-visible bug is fixed here": I agree that it's not easy to trigger manually the bug (when pressing CTRL+C), but I don't see why an user couldn't hit this bug. The race condition is now obvious to me. |
I don't want to spend hours arguing. This issue is sufficiently rare and unlikely in normal conditions that I don't think we should risk regressions by trying to fix it. |
Linux vendors run the full test suite. If the test suite fails, the build of the package fails as well. It's annoying. |
After this change tests are failed when ran with -Werror. $ ./python -Werror -m test -vuall -m 'test_semaphore_tracker_sig*' test_multiprocessing_fork test_multiprocessing_forkserver test_multiprocessing_spawn
... ====================================================================== Traceback (most recent call last):
File "/home/serhiy/py/cpython/Lib/test/_test_multiprocessing.py", line 4562, in test_semaphore_tracker_sigkill
self.check_semaphore_tracker_death(signal.SIGKILL, True)
File "/home/serhiy/py/cpython/Lib/test/_test_multiprocessing.py", line 4526, in check_semaphore_tracker_death
_semaphore_tracker.ensure_running()
File "/home/serhiy/py/cpython/Lib/multiprocessing/semaphore_tracker.py", line 64, in ensure_running
warnings.warn('semaphore_tracker: process died unexpectedly, '
UserWarning: semaphore_tracker: process died unexpectedly, relaunching. Some semaphores might leak. ... Traceback (most recent call last):
File "/home/serhiy/py/cpython/Lib/test/_test_multiprocessing.py", line 4554, in test_semaphore_tracker_sigint
self.check_semaphore_tracker_death(signal.SIGINT, False)
File "/home/serhiy/py/cpython/Lib/test/_test_multiprocessing.py", line 4526, in check_semaphore_tracker_death
_semaphore_tracker.ensure_running()
File "/home/serhiy/py/cpython/Lib/multiprocessing/semaphore_tracker.py", line 64, in ensure_running
warnings.warn('semaphore_tracker: process died unexpectedly, '
UserWarning: semaphore_tracker: process died unexpectedly, relaunching. Some semaphores might leak. ====================================================================== Traceback (most recent call last):
File "/home/serhiy/py/cpython/Lib/test/_test_multiprocessing.py", line 4562, in test_semaphore_tracker_sigkill
self.check_semaphore_tracker_death(signal.SIGKILL, True)
File "/home/serhiy/py/cpython/Lib/test/_test_multiprocessing.py", line 4534, in check_semaphore_tracker_death
sem = ctx.Semaphore()
File "/home/serhiy/py/cpython/Lib/multiprocessing/context.py", line 82, in Semaphore
return Semaphore(value, ctx=self.get_context())
File "/home/serhiy/py/cpython/Lib/multiprocessing/synchronize.py", line 126, in __init__
SemLock.__init__(self, SEMAPHORE, value, SEM_VALUE_MAX, ctx=ctx)
File "/home/serhiy/py/cpython/Lib/multiprocessing/synchronize.py", line 80, in __init__
register(self._semlock.name)
File "/home/serhiy/py/cpython/Lib/multiprocessing/semaphore_tracker.py", line 104, in register
self._send('REGISTER', name)
File "/home/serhiy/py/cpython/Lib/multiprocessing/semaphore_tracker.py", line 111, in _send
self.ensure_running()
File "/home/serhiy/py/cpython/Lib/multiprocessing/semaphore_tracker.py", line 64, in ensure_running
warnings.warn('semaphore_tracker: process died unexpectedly, '
UserWarning: semaphore_tracker: process died unexpectedly, relaunching. Some semaphores might leak. ... Traceback (most recent call last):
File "/home/serhiy/py/cpython/Lib/test/_test_multiprocessing.py", line 4554, in test_semaphore_tracker_sigint
self.check_semaphore_tracker_death(signal.SIGINT, False)
File "/home/serhiy/py/cpython/Lib/test/_test_multiprocessing.py", line 4526, in check_semaphore_tracker_death
_semaphore_tracker.ensure_running()
File "/home/serhiy/py/cpython/Lib/multiprocessing/semaphore_tracker.py", line 64, in ensure_running
warnings.warn('semaphore_tracker: process died unexpectedly, '
UserWarning: semaphore_tracker: process died unexpectedly, relaunching. Some semaphores might leak. ====================================================================== Traceback (most recent call last):
File "/home/serhiy/py/cpython/Lib/test/_test_multiprocessing.py", line 4562, in test_semaphore_tracker_sigkill
self.check_semaphore_tracker_death(signal.SIGKILL, True)
File "/home/serhiy/py/cpython/Lib/test/_test_multiprocessing.py", line 4534, in check_semaphore_tracker_death
sem = ctx.Semaphore()
File "/home/serhiy/py/cpython/Lib/multiprocessing/context.py", line 82, in Semaphore
return Semaphore(value, ctx=self.get_context())
File "/home/serhiy/py/cpython/Lib/multiprocessing/synchronize.py", line 126, in __init__
SemLock.__init__(self, SEMAPHORE, value, SEM_VALUE_MAX, ctx=ctx)
File "/home/serhiy/py/cpython/Lib/multiprocessing/synchronize.py", line 80, in __init__
register(self._semlock.name)
File "/home/serhiy/py/cpython/Lib/multiprocessing/semaphore_tracker.py", line 104, in register
self._send('REGISTER', name)
File "/home/serhiy/py/cpython/Lib/multiprocessing/semaphore_tracker.py", line 111, in _send
self.ensure_running()
File "/home/serhiy/py/cpython/Lib/multiprocessing/semaphore_tracker.py", line 64, in ensure_running
warnings.warn('semaphore_tracker: process died unexpectedly, '
UserWarning: semaphore_tracker: process died unexpectedly, relaunching. Some semaphores might leak. And I'm puzzled by the line issubclass(the_warn.category, UserWarning) |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: