Path: utzoo!mnetor!uunet!husc6!hao!ames!umd5!mimsy!chris
From: chris@mimsy.UUCP (Chris Torek)
Newsgroups: comp.unix.wizards
Subject: Re: Wait, Select, and a SIGCHLD Race Condition
Message-ID: <9771@mimsy.UUCP>
Date: 14 Dec 87 19:30:10 GMT
References: <5105@sol.ARPA> <36350@sun.uucp>
Organization: U of Maryland, Dept. of Computer Science, Coll. Pk., MD 20742
Lines: 85

In article <36350@sun.uucp> jamesa%betelgeuse@Sun.COM (James D. Allen) writes:
>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.

All user-level race conditions result from this; it can be (but does
not have to be) considered a deficiency in the interface.  This very
problem is precisely why I want a signal mask in select's arguments:
so that none of the three kludges are necessary.  (Some of you may
recall my recent diatribe on the subject.)

In summary:

	FASYNC
	select timeout
	longjmp

The first method works only if you are willing to recode everything
to use signals (and you still need select!---but with immediate
timeout); the select timeout works but is somewhat tricky to code;
the longjmp works but only if you have exactly one jump.  I would
probably use the select timeout trick myself.  Here it is in its
full glory:

struct select_goo {
	int	*nfds;			/* points to select's nfds argument */
	struct	timeval *timeout;	/* ... to timeout argument */
	struct	select_goo *inner;	/* previous select, if recursing */
} *select_goo;

catch_sigchld()
{

	child_changed = 1;
	if (select_goo) {
		*select_goo->nfds = 0;	/* saves work in select() */
		timerclear(select_goo->timeout);
	}
}

...
	int nfds, omask, cc;
	fd_set rfd, wfd, xfd;
	struct timeval to;
	struct select_goo goo;

	/* copy these since select or SIGCHLD will modify them */
	nfds = Nfds, rfd = Rfd, wfd = Wfd, xfd = Xfd, to = Timeout;

	/* hold the signal while we build the goo */
	omask = sigblock(sigmask(SIGCHLD));
	if (child_changed) {
		/* a signal already occurred, so skip all this */
		(void) sigsetmask(omask);
		return (0);
	}
	goo.nfds = &nfds;
	goo.timeout = &to;
	goo.inner = select_goo;
	select_goo = &goo;

	/* now safe to release the signal */
	(void) sigsetmask(omask);

	cc = select(nfds, &rfd, &wfd, &xfd, &to);

	/* either the select selected, or the signal hit,
	   or the timeout expired */

	/* undo the goo */
	omask = sigblock(sigmask(SIGCHLD));
	select_goo = goo.inner;

	/* figure out which event occurred */
	if (child_changed) {
		/* the signal hit */
	} else if (cc == 0) {
		/* the timeout expired */
	} else {
		/* the select selected */
	}
	(void) sigsetmask(omask);
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris