* 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
This commit is contained in:
parent
bd4e9e0ca9
commit
2b5cc5ebaf
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue