summaryrefslogtreecommitdiff
path: root/Lib/socketserver.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/socketserver.py')
-rw-r--r--Lib/socketserver.py29
1 files changed, 27 insertions, 2 deletions
diff --git a/Lib/socketserver.py b/Lib/socketserver.py
index 41a3766772..c4d544b372 100644
--- a/Lib/socketserver.py
+++ b/Lib/socketserver.py
@@ -547,8 +547,10 @@ if hasattr(os, "fork"):
timeout = 300
active_children = None
max_children = 40
+ # If true, server_close() waits until all child processes complete.
+ _block_on_close = False
- def collect_children(self):
+ def collect_children(self, *, blocking=False):
"""Internal routine to wait for children that have exited."""
if self.active_children is None:
return
@@ -572,7 +574,8 @@ if hasattr(os, "fork"):
# Now reap all defunct children.
for pid in self.active_children.copy():
try:
- pid, _ = os.waitpid(pid, os.WNOHANG)
+ flags = 0 if blocking else os.WNOHANG
+ pid, _ = os.waitpid(pid, flags)
# if the child hasn't exited yet, pid will be 0 and ignored by
# discard() below
self.active_children.discard(pid)
@@ -621,6 +624,10 @@ if hasattr(os, "fork"):
finally:
os._exit(status)
+ def server_close(self):
+ super().server_close()
+ self.collect_children(blocking=self._block_on_close)
+
class ThreadingMixIn:
"""Mix-in class to handle each request in a new thread."""
@@ -628,6 +635,11 @@ class ThreadingMixIn:
# Decides how threads will act upon termination of the
# main process
daemon_threads = False
+ # If true, server_close() waits until all non-daemonic threads terminate.
+ _block_on_close = False
+ # For non-daemonic threads, list of threading.Threading objects
+ # used by server_close() to wait for all threads completion.
+ _threads = None
def process_request_thread(self, request, client_address):
"""Same as in BaseServer but as a thread.
@@ -647,8 +659,21 @@ class ThreadingMixIn:
t = threading.Thread(target = self.process_request_thread,
args = (request, client_address))
t.daemon = self.daemon_threads
+ if not t.daemon and self._block_on_close:
+ if self._threads is None:
+ self._threads = []
+ self._threads.append(t)
t.start()
+ def server_close(self):
+ super().server_close()
+ if self._block_on_close:
+ threads = self._threads
+ self._threads = None
+ if threads:
+ for thread in threads:
+ thread.join()
+
if hasattr(os, "fork"):
class ForkingUDPServer(ForkingMixIn, UDPServer): pass