summaryrefslogtreecommitdiff
path: root/Lib/socketserver.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/socketserver.py')
-rw-r--r--Lib/socketserver.py73
1 files changed, 40 insertions, 33 deletions
diff --git a/Lib/socketserver.py b/Lib/socketserver.py
index 8332fdf66d..73399115b6 100644
--- a/Lib/socketserver.py
+++ b/Lib/socketserver.py
@@ -131,7 +131,6 @@ __version__ = "0.4"
import socket
import select
-import sys
import os
import errno
try:
@@ -299,7 +298,7 @@ class BaseServer:
"""
try:
request, client_address = self.get_request()
- except socket.error:
+ except OSError:
return
if self.verify_request(request, client_address):
try:
@@ -427,8 +426,12 @@ class TCPServer(BaseServer):
self.socket = socket.socket(self.address_family,
self.socket_type)
if bind_and_activate:
- self.server_bind()
- self.server_activate()
+ try:
+ self.server_bind()
+ self.server_activate()
+ except:
+ self.server_close()
+ raise
def server_bind(self):
"""Called by constructor to bind the socket.
@@ -479,7 +482,7 @@ class TCPServer(BaseServer):
#explicitly shutdown. socket.close() merely releases
#the socket and waits for GC to perform the actual close.
request.shutdown(socket.SHUT_WR)
- except socket.error:
+ except OSError:
pass #some platforms may raise ENOTCONN here
self.close_request(request)
@@ -524,35 +527,39 @@ class ForkingMixIn:
def collect_children(self):
"""Internal routine to wait for children that have exited."""
- if self.active_children is None: return
+ if self.active_children is None:
+ return
+
+ # If we're above the max number of children, wait and reap them until
+ # we go back below threshold. Note that we use waitpid(-1) below to be
+ # able to collect children in size(<defunct children>) syscalls instead
+ # of size(<children>): the downside is that this might reap children
+ # which we didn't spawn, which is why we only resort to this when we're
+ # above max_children.
while len(self.active_children) >= self.max_children:
- # XXX: This will wait for any child process, not just ones
- # spawned by this library. This could confuse other
- # libraries that expect to be able to wait for their own
- # children.
- try:
- pid, status = os.waitpid(0, 0)
- except os.error:
- pid = None
- if pid not in self.active_children: continue
- self.active_children.remove(pid)
-
- # XXX: This loop runs more system calls than it ought
- # to. There should be a way to put the active_children into a
- # process group and then use os.waitpid(-pgid) to wait for any
- # of that set, but I couldn't find a way to allocate pgids
- # that couldn't collide.
- for child in self.active_children:
try:
- pid, status = os.waitpid(child, os.WNOHANG)
- except os.error:
- pid = None
- if not pid: continue
+ pid, _ = os.waitpid(-1, 0)
+ self.active_children.discard(pid)
+ except InterruptedError:
+ pass
+ except ChildProcessError:
+ # we don't have any children, we're done
+ self.active_children.clear()
+ except OSError:
+ break
+
+ # Now reap all defunct children.
+ for pid in self.active_children.copy():
try:
- self.active_children.remove(pid)
- except ValueError as e:
- raise ValueError('%s. x=%d and list=%r' % (e.message, pid,
- self.active_children))
+ pid, _ = os.waitpid(pid, os.WNOHANG)
+ # if the child hasn't exited yet, pid will be 0 and ignored by
+ # discard() below
+ self.active_children.discard(pid)
+ except ChildProcessError:
+ # someone else reaped it
+ self.active_children.discard(pid)
+ except OSError:
+ pass
def handle_timeout(self):
"""Wait for zombies after self.timeout seconds of inactivity.
@@ -574,8 +581,8 @@ class ForkingMixIn:
if pid:
# Parent process
if self.active_children is None:
- self.active_children = []
- self.active_children.append(pid)
+ self.active_children = set()
+ self.active_children.add(pid)
self.close_request(request)
return
else: