Commit 20cd54fc authored by Jason Madden's avatar Jason Madden

Allow resetting and ignoring SIGCHLD. Fixes #696.

parent c257a0d9
......@@ -16,7 +16,10 @@
``sendall``.
- gevent's SSL socket's ``sendall`` method should no longer raise ``SSL3_WRITE_PENDING``
in rare cases when sending large buffers. Reported in :issue:`317`.
- ``gevent.signal`` now allows resetting (SIG_DFL) and ignoring (SIG_IGN) the
SIGCHLD signal at the process level (although this may allow race
conditions with libev child watchers). Reported in :issue:`696` by
Adam Ning.
1.1rc1 (Nov 14, 2015)
=====================
......
......@@ -61,6 +61,11 @@ def signal(signalnum, handler):
the builtin :func:`signal.signal` would be triggered either;
libev typically overwrites such a handler at the C level. At
the very least, it's full of race conditions.)
.. note::
Use of ``SIG_IGN`` and ``SIG_DFL`` may also have race conditions
with libev child watchers and the :mod:`gevent.subprocess` module.
"""
if signalnum != _signal.SIGCHLD:
return _signal_signal(signalnum, handler)
......@@ -75,6 +80,11 @@ def signal(signalnum, handler):
old_handler = getsignal(signalnum)
global _child_handler
_child_handler = handler
if handler == _signal.SIG_IGN or handler == _signal.SIG_DFL:
# Allow resetting/ignoring this signal at the process level.
# Note that this conflicts with gevent.subprocess and other users
# of child watchers.
_signal_signal(signalnum, handler)
return old_handler
......
# Mimics what gunicorn workers do: monkey patch in the child process
# and try to reset signal handlers to SIG_DFL.
# NOTE: This breaks again when gevent.subprocess is used, or any child
# watcher.
import os
import sys
import signal
def handle(*args):
if not pid:
# We only do this is the child so our
# parent's waitpid can get the status.
# This is the opposite of gunicorn.
os.waitpid(-1, os.WNOHANG)
# The signal watcher must be installed *before* monkey patching
signal.signal(signal.SIGCHLD, handle)
pid = os.fork()
if pid: # parent
try:
_, stat = os.waitpid(pid, 0)
except OSError:
# Interrupted system call
_, stat = os.waitpid(pid, 0)
assert stat == 0, stat
else:
import gevent.monkey
gevent.monkey.patch_all()
signal.signal(signal.SIGCHLD, signal.SIG_DFL)
# Under Python 2, os.popen() directly uses the popen call, and
# popen's file uses the pclose() system call to
# wait for the child. If it's already waited on,
# it raises the same exception.
# Python 3 uses the subprocess module directly which doesn't
# have this problem.
f = os.popen('true')
f.close()
sys.exit(0)
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