summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHelmut Grohne <helmut@subdivi.de>2019-03-10 17:49:00 +0100
committerHelmut Grohne <helmut@subdivi.de>2019-03-10 17:49:00 +0100
commit44bdfe2a595ce06dfda3d00ee0cf65e565c3cbea (patch)
tree281f410fd9ac2bcc7ccb7b326dcb9a034dad4eb0
parenta10a7217cf963731e2566c1aa7cb6f7b96152b59 (diff)
downloadwsgitools-44bdfe2a595ce06dfda3d00ee0cf65e565c3cbea.tar.gz
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.
-rw-r--r--wsgitools/scgi/forkpool.py15
1 files 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):
"""