From: terry@cs.weber.edu (A Wizard of Earth C)
Subject: Re: Queueing of signals
Keywords: SIGCHLD, signals, queueing, sigvec
Organization: Weber State University  (Ogden, UT)
Date: Fri, 14 Aug 92 07:26:25 GMT

You know, if I had any sense, I'd be going to bed right this instant...

In article <1992Aug13.160824.11077@bwdls61.bnr.ca> gwaters@bwdls139.bnr.ca (Glenn Waters) writes:
>I have a program that seems to lose SIGCHLD signals. There are two (or more)
>processes that die simultaneously -- thus generating two SIGCHLDs
>to the parent. I only seem to get the first SIGCHLD.
>
>Are the signals queued? I believe not.
>
>What is the correct method of catching the subsequent child deaths that are
>not queued?

1)	Signals aren't queued
2)	POSIX signals aren't queued (they almost say they are but not quite)
3)	You can't catch multiple instances of signals which occur prior/during
	handler invocation, since a signal is a persistant condition, not an
	event.  It may be set by an event (the event itself having been queued),
	but how many time a bit was set high is undetectable.


HOWEVER:

For child deaths, you CAN sneaky around it:


/*
 * My routine macduff, which handles at least one SIGCLD per cluster of
 * them due to the nature of signals...
 */

int	the_bell_tolled = 0;

macduff()
{
	/*
	 * Mother!  I am killed! --MacDuff in "Macbeth" by W. Shakespere;
	 * look it up on your NeXT.
	 */
	the_bell_tolled = 1;
}

/*
 * My initialization, living somewhere...
 */
...
signal( SIGCLD, macduff);
...

/*
 * My main loop, living somewhere (preferrably after my initialization 8-)...
 */
for(;;)
	...
	/*
	 * Check for the bell...
	 */
	if( the_bell_tolled) {
		/*
		 * "Ah! I see you have the machine that goes *BING*!"
		 *	- J. Cleese, "The Meaning of Life"
		 */
		the_bell_tolled = 0;	/* shut off the bell BEFORE reaping*/
		grim_reaper();		/* ...ask for whom the bell tolled*/
		...
	}
}

/* NOTREACHED*/

exit( 0);	/* the end of my program*/


/*
 * My routine grim_reaper, who takes the souls of the dead child processes
 * to silicon heaven (so to speak, and only in the most general terms).
 *
 * "No silicon heaven!?! Ridiculous!  Where would all the calculators go?"
 *	-- Kryten, "Red Dwarf"
 */
grim_reaper()
{
	int	pid;		/* pid_t for puritans*/
	int	st;

	/*
	 * You may have to use a different "scythe": ie: wait3 instead of
	 * waitpid, or whatever you have instead that returns the pid and
	 * status of a reaped child process if the is one but doesn't
	 * hang otherwise.
	 */
	while( ( pid = waitpid( -1, &st, WNOHANG)) > 0)  {
		printf( "Child PID %d exited with %d\n", pid, st);
		...
	}
}



	What happens is that one or more child deaths result in a signal
SIGCLD being caught by macduff.  He sets a flag (the_bell_tolls).  Then
SIGCLD's are allowed to happen again.  This way, regardless of the number
of SIGCLDs, you always know that there was 0 > count < n of them.  Since
the handler is not in operation at the time that the actual handling is
to [conditionally] occur, handling the SIGCLD's will not cause them to
be blocked for the duration.  By setting the flag to zero before waking
up Bill and Ted's friend to deal with the handling, we make sure that
anything caught while handling will result in another call to the handler,
and that there is thus not a window where we can "miss" one or more SIGCLDs
(SIGChiLDren?).  This translates the SIGCLD from a "one or more processes
have died" *flag* into a "better see how many died" *event*.  Mr. Reaper
then goes out and reaps each of the child processes.  If you were interested
in precisely which child died (ie: for some reason your children were not
homogeneous processes, like fork/exec), you have the PID of the dead child,
and can do a reverse-lookup to compare against an array of child PIDs (which
are probably structure element members) which you cleverly saved off when
you forked, and can act accordingly.

	Delayed handling of signals is useful in any case where the cause
of the signal is determinable and persistant (SIGPOLL on a stream head,
for instance, where determination of the culprit can be made using the
select/poll system calls), but not as a general mechanism.  This means you
should probably not use multiple signal generators for which you are handling
signals (ie: child deaths and stream data available) in the same program
unless you can be guaranteed of a signal being blocked for delivery instead
of ingnored when you're handling the other signal.

	Signals are queued in the POSIX 1003.4 spec, but this is still
subject to change and probably wont be frozen one way or the other until
late 93/early 94; until then, we'll all have to just limp along...


					Terry Lambert
					terry_lambert@gateway.novell.com
					terry@icarus.weber.edu
---
Any opinions in this posting are my own and not those of my present
or previous employers.
-- 
-------------------------------------------------------------------------------
                                                       terry@icarus.weber.edu
 "I have an 8 user poetic license" - me
-------------------------------------------------------------------------------