Re: POSIX wait and SIGCHLD

scharf@EMBL-Heidelberg.DE
Wed, 22 Mar 1995 12:07:59 +0100

> ...
> | Later he uses this in the following way:
> ...
> | #ifdef SIGTSTP
> | signal(SIGCLD, sig_child); /* BSD */
> | #else
> | signal(SIGCLD, SIG_IGN); /* System V */
> | #endif
>
> I beg your pardon, Richard Stevens said to use SIGCLD on BSD? Not SIGCHLD?

On page 82 he really writes SIGCLD for both cases !?

> | Well, using SIGTSTP as indicator for BSD seems to be a funny trick...
>
> By this measure nearly all UNIX computers are BSD today, certainly any
> that are likely to run python. And it's sort of true, but unfortunately
> not entirely, even on BSD 4.4!

I agree the SIGTSTP is very strange...

> Anyway, I thought I'd pass on some experimental results from modern,
> generally POSIX-compliant UNIX implementations. If I SIGCHLD (not
> SIGCLD) to SIG_IGN, AIX 3.2.5 doesn't leave a zombie child, but DEC
> OSF/1 does. IBM documents this feature for AIX. I can test this
> elsewhere later, if anyone's interested, but right off it seems like
> something that would be hard to use in a portable way. (The above
> tests were done in C, not python.)

I agree, with all this different semantics it is very difficult to do the
SIGC[H]?LD handling in a system independ portable fashion. That's the reason,
why I proposed, that WNOHANG should be exported from the posix module.

What I want to do is the following:

def wait_some_children():
while 1:
pid,status=posix.waitpid(-1,posix.WNOHANG)
if not pid:
return

I then call from time to time (e.g before a fork) wait_some_children(). There
may be for some time some unwaited children, but I 'll get them all.
I can also keep track of my children:

gChildren={}

def wait_some_children():
while gChildren:
pid,status=posix.waitpid(-1,posix.WNOHANG)
if not pid:
return
del gChildren[pid]

def main():
#....
while create_new_process():
pid=posix.fork():
if pid: # parent
gChildren[pid]=pid
wait_some_children()
#...
else: # child
#...
sys.exit(0)

What I really want to to is to write a tcp/ip server which forks and does not
create too many zombees.

Looking at the NCSA http demon (which looks very much like the server skeleton
described by Richard Stevens ... may they have read his book ;-):

#ifdef BSD
void ign() {
#ifndef NEXT
int status;
#else
union wait status;
#endif
pid_t pid;

while( (pid = wait3(&status, WNOHANG, NULL)) > 0);
}
#endif

void set_signals() {
/*....*/
#ifdef BSD
signal(SIGCHLD,(void (*)())ign);
#else
signal(SIGCHLD,SIG_IGN);
#endif
}

Looking at BRIAN KANTOR nntp deamon:

/*
* reaper -- reap children who are ready to die.
* Called by signal.
*
* Parameters: None.
*
* Returns: Nothing.
*
* Side effects: None.
*/

reaper()
{
#ifndef USG
union wait status;

while (wait3(&status, WNOHANG, (struct rusage *)0) > 0)
;
#endif /* not USG */
}

#ifdef USG
(void) signal(SIGCLD, SIG_IGN);
#else /* !USG */
(void) signal(SIGCHLD, reaper);
#endif /* USG */

It seems whatever you do -- you need WNOHANG (and wait3 or waitgrp)!

Python could provide a default ign_chld handler. On System V this would just be
SIG_IGN and on BSD the wait3(.., WNOHANG,..) handler. But maybe this is too
specialized.

Without handling children I see no chance to create deamons which fork
themselves to open sockets like httpd, nntpd etc, because of the zombies.

Michael

--
 ___   _  _   ___   _    
| __) | \/ | |   ) | |   Michael Scharf
| _)  |    | | -<  | |_  EMail: scharf@EMBL-Heidelberg.de
|___) |_||_| |___) |___) http://www.EMBL-Heidelberg.de/~scharf/