tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: SIGCHLD and sigaction()



>>> When I install a SIGCHLD handler via sigaction() using SA_SIGINFO,
>>> is it guaranteed that my handler is called (at least) once per
>>> death-of-a-child?
>> "Maybe."  It depends on how portable you want to be.
>> [...]
> While we're on this topic. Unix signals don't exactly work like
> hardware interrupts anyhow, I suspect, and it's a thing that have
> constantly befuddled me.

(Caveat: this is all just my understanding.  I think it's accurate, but
I welcome corrections.)

No, they don't.  To the extent that they do, they work like (latched)
edge-triggered interrupts.  There is no signal analog to a
level-triggered interrupt.  And, as you say, there are some important
differences even beyond that.

> As far as I can tell, there is a problematic race condition in the
> old signal mechanism, and that is the reason (I believe) why the new
> semantics were introduced).

I think you are right.  But it's not just "old" and "new".  There are
really old signal semantics, where the handler is uninstalled, I think
it is, when the signal is delivered, and it's up to the code to
reinstall it.  This is vulnerable to, if nothing else, the race where a
second signal arrives before the handler gets reinstalled, though
that's less important for SIGCHLD (see below).  (There may be an even
older form of signal handling, but if so I know nothing about it.)

This then led to (so-called) reliable signals, where the handler stays
installed (or at least can be set to do so) but signals can be blocked,
and get blocked (or, again, at least can be set to be) when the handler
is called.  However, there is still only a single pending bit per
signal.  I think these came in sometime in the 4BSD era, but I don't
recall details - indeed, I'm not sure I ever knew details.

Turning SIGCHLD into something queued, something more like bytes in a
pipe, is, in my perception, more recent yet.  I'm not sure who invented
them (but see below).

There are traces of the first form in modern NetBSD, in the form of the
SA_RESETHAND bit.  I don't *think* that gives full unreliable-signal
semantics, but I haven't checked in enough detail to be sure - I think
you'd also need an SA_DONTBLOCK flag or something of the sort, or the
handler would have to explicitly unblock the signal.

> You have two child processes.  One exit, and you get into your signal
> handler.  In there you then call wait to reap the child and process
> things.  You then call wait again, and repeat until there are no
> children left to reap, as you only get one signal, even if you get
> multiple children that exits.  When no more unreaped children exist,
> you exit the signal handler, and a new signal can be delivered.

Right.

> However, what happens if the second child exists between the call to
> wait, and the exit from the signal handler?  It would seem the signal
> would get lost, since we are in the process of handling the signal,
> and a new signal is not delivered during this time.

If you're using unreliable signals - the first sort I outlined above -
then yes, there is either this race, or, if you reinstall the handler
before you do your last wait call, a different race.  (Provided your
handler doesn't mind being called recursively between reinstall and
return, this may be tolerable.)

If you're using reliable signals but without queued SIGCHLD, this is
not a problem, because the second SIGCHLD (and any additional later
SIGCHLDs) will set the pending bit for SIGCHLD.  As soon as you return
from the handler (or explicitly unblock the signal), it will be
delivered.

> Now, have I misunderstood something about how non-queued signal
> handling works, or is/was there a problem there?

There was, but it was a problem with the oldest of the above three
kinds of signal.  Queued SIGCHLD was not necessary for it - I don't
understand what problem queued SIGCHLD was invented to address.  The
only thing I can think of was that it came from SRV4, which had a NIH
attitude towards BSD reliable signals, so they invented queued SIGCHLD
to get reliable child death handling, and then someone (POSIX maybe?)
decided it would be good to include all of both mechanisms.

/~\ The ASCII				  Mouse
\ / Ribbon Campaign
 X  Against HTML		mouse%rodents-montreal.org@localhost
/ \ Email!	     7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B


Home | Main Index | Thread Index | Old Index