[Python-checkins] r61106 - in python/trunk/Lib: SocketServer.py test/test_socketserver.py
Jeffrey Yasskin
jyasskin at gmail.com
Fri Feb 29 07:57:50 CET 2008
On Thu, Feb 28, 2008 at 10:46 PM, Neal Norwitz <nnorwitz at gmail.com> wrote:
>
> On Thu, Feb 28, 2008 at 10:03 AM, jeffrey.yasskin
> <python-checkins at python.org> wrote:
> > Author: jeffrey.yasskin
> > Date: Thu Feb 28 19:03:15 2008
> > New Revision: 61106
> >
> > Modified:
> > python/trunk/Lib/SocketServer.py
> > python/trunk/Lib/test/test_socketserver.py
> > Log:
> > Prevent SocketServer.ForkingMixIn from waiting on child processes that it
> > didn't create, in most cases. When there are max_children handlers running, it
> > will still wait for any child process, not just handler processes.
> >
> >
> > Modified: python/trunk/Lib/SocketServer.py
> > ==============================================================================
> > --- python/trunk/Lib/SocketServer.py (original)
> > +++ python/trunk/Lib/SocketServer.py Thu Feb 28 19:03:15 2008
> > @@ -440,18 +440,30 @@
> >
> > def collect_children(self):
> > """Internal routine to wait for children that have exited."""
> > - while self.active_children:
> > - if len(self.active_children) < self.max_children:
> > - options = os.WNOHANG
> > - else:
> > - # If the maximum number of children are already
> > - # running, block while waiting for a child to exit
> > - options = 0
> > + if self.active_children is None: return
> > + 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, options)
> > + pid, status = os.waitpid(0, options=0)
> > except os.error:
> > pid = None
> > - if not pid: break
> > + 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
> > try:
> > self.active_children.remove(pid)
> > except ValueError, e:
>
> The handling of the exception when removing from active_children seems
> backwards to me. In the first loop where we wait on any child, that
> can return a pid that we might not be expecting. ISTM there should be
> a try/except around that one. It probably should swallow the error.
> I suppose a nicer API would keep the pid and status and make it
> available (even though no one will ever check it).
That's what the "if pid not in self.active_children: continue" is for.
Once that passes, if there's no race, the pid can definitely be
removed with no exception. It's an expected situation, so using the
exception to ignore it doesn't seem appropriate.
> In the second loop (the for loop), we only wait on children we know
> should be in the list. If they aren't in the list, this code has a
> bug. I think the try/except was added for additional debugging.
> Hopefully the problem has been fixed, so the extra debugging should no
> longer be necessary.
Perhaps the ValueError thrown by list.remove() should include that
information. It'd be reasonable to remove this try/except anyway.
--
Namasté,
Jeffrey Yasskin
More information about the Python-checkins
mailing list