Skip to content

Commit

Permalink
arbiter: Handle SIGCHLD in normal/main process context
Browse files Browse the repository at this point in the history
... as opposed to in signal context. This is beneficial, since it
means that we can, in a signal safe way, print messages about why
e.g. a worker stopped its execution.

The code is still not completely signal safe, since it uses a list to
push what signal was caught. This is addressed in the following commit.
  • Loading branch information
sylt committed Feb 2, 2024
1 parent 88fc4a4 commit b6d8524
Showing 1 changed file with 6 additions and 4 deletions.
10 changes: 6 additions & 4 deletions gunicorn/arbiter.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class Arbiter(object):
# I love dynamic languages
SIG_QUEUE = []
SIGNALS = [getattr(signal, "SIG%s" % x)
for x in "HUP QUIT INT TERM TTIN TTOU USR1 USR2 WINCH".split()]
for x in "CHLD CLD HUP QUIT INT TERM TTIN TTOU USR1 USR2 WINCH".split()]
SIG_NAMES = dict(
(getattr(signal, name), name[3:].lower()) for name in dir(signal)
if name[:3] == "SIG" and name[3] != "_"
Expand Down Expand Up @@ -186,7 +186,6 @@ def init_signals(self):
# initialize all signals
for s in self.SIGNALS:
signal.signal(s, self.signal)
signal.signal(signal.SIGCHLD, self.handle_chld)

def signal(self, sig, frame):
if len(self.SIG_QUEUE) < 5:
Expand Down Expand Up @@ -237,10 +236,12 @@ def run(self):
self.pidfile.unlink()
sys.exit(-1)

def handle_chld(self, sig, frame):
def handle_cld(self):
"SIGCHLD handling"
self.reap_workers()
self.wakeup()

def handle_chld(self):
self.handle_chld()

def handle_hup(self):
"""\
Expand Down Expand Up @@ -393,6 +394,7 @@ def stop(self, graceful=True):
self.kill_workers(sig)
# wait until the graceful timeout
while self.WORKERS and time.time() < limit:
self.reap_workers()
time.sleep(0.1)

self.kill_workers(signal.SIGKILL)
Expand Down

0 comments on commit b6d8524

Please sign in to comment.