bpo-31151: Add socketserver.ForkingMixIn.server_close() (#3057)

* Add socketserver.ForkingMixIn.server_close()

bpo-31151: socketserver.ForkingMixIn.server_close() now waits until
all child processes completed to prevent leaking zombie processes.

* Fix test on Windows which doesn't have ForkingMixIn
diff --git a/Lib/socketserver.py b/Lib/socketserver.py
index 6e1ae9f..df17114 100644
--- a/Lib/socketserver.py
+++ b/Lib/socketserver.py
@@ -547,7 +547,7 @@
         active_children = None
         max_children = 40
 
-        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
@@ -571,7 +571,8 @@
             # 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)
@@ -620,6 +621,10 @@
                     finally:
                         os._exit(status)
 
+        def server_close(self):
+            super().server_close()
+            self.collect_children(blocking=True)
+
 
 class ThreadingMixIn:
     """Mix-in class to handle each request in a new thread."""