From 44bdfe2a595ce06dfda3d00ee0cf65e565c3cbea Mon Sep 17 00:00:00 2001 From: Helmut Grohne Date: Sun, 10 Mar 2019 17:49:00 +0100 Subject: scgi.forkpool: fix SIGTERM handler in the presence of PEP475 Since PEP475 or Python 3.5, select retries an interrupted system call. However, we were relying on the previous behaviour. Thus we must interrupt select using some other measure. Another socketpair is created and the signal handler transfers a byte on shutdown. --- wsgitools/scgi/forkpool.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/wsgitools/scgi/forkpool.py b/wsgitools/scgi/forkpool.py index b2bedcc..20943fc 100644 --- a/wsgitools/scgi/forkpool.py +++ b/wsgitools/scgi/forkpool.py @@ -236,6 +236,7 @@ class SCGIServer(object): self.cpulimit = cpulimit self.timelimit = timelimit self.server = None # becomes a socket + self.sigpipe = None # becomes a pair socketpair endpoints # maps filedescriptors to WorkerStates self.workers = {} self.running = False @@ -262,6 +263,7 @@ class SCGIServer(object): self.server.listen(5) else: self.server = self.reusesocket + self.sigpipe = socket.socketpair() self.running = True while self.running: while (len(self.workers) < self.minworkers or # less than min @@ -269,13 +271,18 @@ class SCGIServer(object): not len([w for w in # no inactive self.workers.values() if w.state == 0]))): self.spawnworker() + rs = list(self.workers.keys()) + rs.append(self.sigpipe[0]) try: - rs, _, _ = select.select(self.workers.keys(), [], []) + rs, _, _ = select.select(rs, [], []) except select.error as e: if e[0] != errno.EINTR: raise rs = [] for s in rs: + if s == self.sigpipe[0]: + self.sigpipe[0].recv(1) + continue try: data = self.workers[s].sock.recv(1) except socket.error: @@ -297,6 +304,9 @@ class SCGIServer(object): if self.reusesocket is None: self.server.close() self.server = None + self.sigpipe[0].close() + self.sigpipe[1].close() + self.sigpipe = None self.killworkers() def killworkers(self, sig=signal.SIGTERM): @@ -321,8 +331,9 @@ class SCGIServer(object): """ if self.ischild: sys.exit() - else: + elif self.running: self.running = False + self.sigpipe[1].send(b' ') def sigxcpuhandler(self, sig=None, stackframe=None): """ -- cgit v1.2.3