Path: utzoo!mnetor!uunet!seismo!sundc!pitstop!sun!betelgeuse!jamesa
From: jamesa%betelgeuse@Sun.COM (James D. Allen)
Newsgroups: comp.unix.wizards
Subject: Re: Wait, Select, and a SIGCHLD Race Condition
Message-ID: <36350@sun.uucp>
Date: 13 Dec 87 23:45:32 GMT
References: <5105@sol.ARPA>
Sender: news@sun.uucp
Lines: 56
Summary: Longjmp also works

In article <5105@sol.ARPA>, stuart@cs.rochester.edu writes:
> I need advice (or sympathy) for handling a race condition in 4.3BSD
> flavored UNIX.  Briefly, I want to use wait3 to reap all the dead or
> stopped children of a process, then use select to wait for the first
> new IO or child activity.  Sketch something like this:
> 
>   while (0 < (pid = wait3(..., WNOHANG, ...))) {
>     /* do something with child */
>   }
> /* XXX Race condition is here */
>   numfds = select(...);
	et cetera

This race condition is intriguing because it arises from "instruction
atomization" in the application program, and NOT due to limitations in the
Unix system interface.  Two correct solutions have been posted which take
advantage of a Unix feature (FASYNC in one case, select timeout in the
other).  It's worth noting, however, that the application code can detect
and fix the race without OS assistance, as shown in the crude fragment:

sig_catcher()
{
	caught_signal = TRUE;
	if (possible_race)
		longjmp(jmp_buffer, 1);
}
wait_for_event()
{
	...
	if (setjmp(jmp_buffer)) {
	    signalled:
		possible_race = FALSE;
	  /* process the signal */
		caught_signal = FALSE;
	} else {
		possible_race = TRUE;
		if (caught_signal)
			goto signalled;
		numfds = select(...);
	/*
	 * No longer need to check EINTR!!
	 *	if (numfds < 0 && errno == EINTR)
	 *		goto signalled;
	 */
		possible_race = FALSE;
	  /* process the select */
	}
	...
}

I don't know how to do this without `longjmp' (or something even uglier).

> 
> Stu Friedberg  {ames,cmcl2,rutgers}!rochester!stuart  stuart@cs.rochester.edu

James Allen      {ucbvax,hplabs,seismo}!sun!betelgeuse!jamesa