Re: posix.waitpid(pid,WNOHANG) ??

Michael Scharf (scharf@EMBL-Heidelberg.DE)
21 Mar 1995 19:19:37 +0100

In article <9503211546.AA07503=guido@voorn.cwi.nl> Guido.van.Rossum@cwi.nl writes:

> > Q: Is there another way to wait without hanging?
> >
> > I tryied to install a signal handler on SIGCHLD. But for some reasons, I
> > don't wait for all children, because some signals get lost, or even worse
> > I get into a state, where I don't get any SIGCHLD signal anymore. After a
> > while my process can't fork anymore because there are too many unwaited
> > children (on irix 6.0.1) :-(.
> There's undocumented special code in signalmodule.c which requires
> your handler to re-instate the signal handler for this signal, because
> otherwise the two-stage way of handling signals in Python would cause
> infinite recursion given the way this signal is generated (if there's
> still a child waiting when you return from the C signal handler, the
> signal is sent again by the OS). I don't know if this code works
> correctly -- in fact I don't know what the guaranteed and actual
> semantics of SIGCHLD are in Posix and other Unix versions.

It was me who brought up the problem with the SIGCHLD :-). In the meantime I
read in the 'UNIX Network Programming' bible [UNIX Network Programming';
W. Richard Stevens; Prentice Hall; 1990]. Stevens points out, that SIGCLD under
System V has a special semantics: if SIGCLD is set to SIG_IGN, then exited
children do not become zombies. To emulate the same under 4.3BSD based UNIX he
suggests the following handler:

#include <sys/wait.h>
#include <signal.h>
/* Beware that the calling process may get an interupted system call
* when we return, so the had better handle that.
*/
sig_child()
{
#ifdef BSD
int pid;
union wait status;
while ( pid = wait3(&status, WNOHANG, (struct rusage*) 0 )) > 0)
;
#endif /* BSD */
}

Later he uses this in the following way:

...
#ifdef SIGTSTP
signal(SIGCLD, sig_child); /* BSD */
#else
signal(SIGCLD, SIG_IGN); /* System V */
#endif

Well, using SIGTSTP as indicator for BSD seems to be a funny trick...
>From which I would conclude the following python code:

def is_BSD():
try:
# funny way to find out if this is SYS V
from signal import SIGTSTP
return 1
except ImportError:
return 0

def sig_child():
import posix
while 1:
# wait all dead children...
pid,status=posix.waitpid(-1,posix.WNOHANG)
if not pid:
# done
return
def ignore_children():
import signal
if is_BSD():
signal.signal(signal.SIGCHLD,sig_child)
else:
signal.signal(signal.SIGCHLD,signal.SIG_IGN)

Ok, I'm not sure if this is_BSD() is a good idea or not. One could
just always install the sig_chld() handler since you patched the signal module
anyway ...

> > Q: Would it make sense to export WNOHANG from the posix module?
> Yes. It's not in the current beta of 1.2 and I would prefer to add as
> few things as possible. However if you come up with a clean patch for
> posixmodule.c that adds these wait-related symbols, I might be
> convinced to add them. (Something similar has already been done with
> socket related symbols.)

Here's a patch based on the newest posixmodule.c -- I hope it's clean enough

Michael :-)

--- posixmodule.c.~1~ Tue Mar 21 16:55:00 1995
+++ posixmodule.c Tue Mar 21 17:23:03 1995
@@ -1468,6 +1468,24 @@
{NULL, NULL} /* Sentinel */
};

+#ifdef HAVE_WAITPID
+/* Convenience routine to export an integer value.
+ For simplicity, errors (which are unlikely anyway) are ignored. */
+
+static void
+BUILD_FUNC_DEF_3(insint,PyObject *,d,char *,name,int,value)
+{
+ PyObject *v = PyInt_FromLong((long) value);
+ if (v == NULL) {
+ /* Don't bother reporting this error */
+ PyErr_Clear();
+ }
+ else {
+ PyDict_SetItemString(d, name, v);
+ Py_DECREF(v);
+ }
+}
+#endif /* HAVE_WAITPID */

#ifdef NT
void
@@ -1484,6 +1502,12 @@
fatal("can't define nt.environ");
DECREF(v);

+#ifdef HAVE_WAITPID
+# ifdef WNOHANG /* let's be shure :-) */
+ insint(d, "WNOHANG", WNOHANG);
+# endif /* WNOHANG */
+#endif /* HAVE_WAITPID */
+
/* Initialize nt.error exception */
PosixError = newstringobject("nt.error");
if (PosixError == NULL || dictinsert(d, "error", PosixError) != 0)
@@ -1503,6 +1527,12 @@
if (v == NULL || dictinsert(d, "environ", v) != 0)
fatal("can't define posix.environ");
DECREF(v);
+
+#ifdef HAVE_WAITPID
+# ifdef WNOHANG /* let's be shure :-) */
+ insint(d, "WNOHANG", WNOHANG);
+# endif /* WNOHANG */
+#endif /* HAVE_WAITPID */

/* Initialize posix.error exception */
PosixError = newstringobject("posix.error");

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