diff options
author | Antoine Pitrou <pitrou@free.fr> | 2017-06-13 07:46:06 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-06-13 07:46:06 (GMT) |
commit | 2b5cc5ebaff41445200753f1a69fd4e6a9475a1e (patch) | |
tree | e5d70f0ba342a9f6cfe79329abfbb705e17a89be /Lib/multiprocessing | |
parent | bd4e9e0ca96dabf33605d9b1fd1e0562ece8ae18 (diff) | |
download | cpython-2b5cc5ebaff41445200753f1a69fd4e6a9475a1e.zip cpython-2b5cc5ebaff41445200753f1a69fd4e6a9475a1e.tar.gz cpython-2b5cc5ebaff41445200753f1a69fd4e6a9475a1e.tar.bz2 |
bpo-30643: Fix race condition in signal wakeup in forkserver (followup to PR #1989) (#2139)
* Fix race condition in signal wakeup in forkserver (followup to PR #1989)
There's an admittedly well-known race condition where ECHILD can arrive
just before the C function epoll_wait() and the latter wouldn't therefore
return EINTR. The solution is to use set_wakeup_fd(), which was designed
to avoid such race conditions.
* Reset wakeup fd in child
Diffstat (limited to 'Lib/multiprocessing')
-rw-r--r-- | Lib/multiprocessing/forkserver.py | 12 |
1 files changed, 8 insertions, 4 deletions
diff --git a/Lib/multiprocessing/forkserver.py b/Lib/multiprocessing/forkserver.py index ddbd0c2..7010515 100644 --- a/Lib/multiprocessing/forkserver.py +++ b/Lib/multiprocessing/forkserver.py @@ -150,15 +150,15 @@ def main(listener_fd, alive_r, preload, main_path=None, sys_path=None): util._close_stdin() sig_r, sig_w = os.pipe() + os.set_blocking(sig_r, False) os.set_blocking(sig_w, False) def sigchld_handler(*_unused): - try: - os.write(sig_w, b'.') - except BlockingIOError: - pass + # Dummy signal handler, doesn't do anything + pass # letting SIGINT through avoids KeyboardInterrupt tracebacks + # unblocking SIGCHLD allows the wakeup fd to notify our event loop handlers = { signal.SIGCHLD: sigchld_handler, signal.SIGINT: signal.SIG_DFL, @@ -166,6 +166,9 @@ def main(listener_fd, alive_r, preload, main_path=None, sys_path=None): old_handlers = {sig: signal.signal(sig, val) for (sig, val) in handlers.items()} + # calling os.write() in the Python signal handler is racy + signal.set_wakeup_fd(sig_w) + # map child pids to client fds pid_to_fd = {} @@ -252,6 +255,7 @@ def main(listener_fd, alive_r, preload, main_path=None, sys_path=None): def _serve_one(child_r, fds, unused_fds, handlers): # close unnecessary stuff and reset signal handlers + signal.set_wakeup_fd(-1) for sig, val in handlers.items(): signal.signal(sig, val) for fd in unused_fds: |