From 44bdfe2a595ce06dfda3d00ee0cf65e565c3cbea Mon Sep 17 00:00:00 2001
From: Helmut Grohne <helmut@subdivi.de>
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(-)

(limited to 'wsgitools/scgi')

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