Commit 2b5cc5eb authored by Antoine Pitrou's avatar Antoine Pitrou Committed by GitHub

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
parent bd4e9e0c
......@@ -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:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment