SIGCONT occurs after a SIGTERM
Chris Torek
torek at elf.ee.lbl.gov
Fri Feb 22 03:17:47 AEST 1991
>In article <10007 at dog.ee.lbl.gov> I wrote:
>>Signals are not queued.
In article <2588 at inews.intel.com> bhoughto at hopi.intel.com
(Blair P. Houghton) writes:
>Something's stacking them up.
Well, not really:
>I've run into situations more than once where I've tried to
>stop a process and the stop has hung, usually due to
>something else's being stuck (an NFS access, e.g.)
I have no idea what `the stop has hung' means.
>I've sent the stop again, and when the block clears I see the
>process stop. When I tell the process to continue, the
>first thing it does is stop itself again.
>Who's doing it? The kernel or csh(1)? The tty driver? Or
>is it just a matter of a stuck process queue?
The most likely cause is the program itself. (This also depends on which
stop signal you use.)
A number of programs contain code resembling the following:
/* broken function to catch SIGTSTP (^Z) */
void
catch_stop()
{
/* put the terminal modes back */
clean_tty();
/* reenable stops */
signal(SIGTSTP, SIG_DFL); /* bug */
/* stop ourselves */
kill(0, SIGTSTP); /* bug */
/* resumes here */
signal(SIGTSTP, catch_stop);
dirty_tty();
}
This particular catcher is full of race conditions. The most interesting
problem, however, is the
kill(0, SIGTSTP);
This sends another stop signal to the entire process group. If there
are two processes in a pipe, both using code like this, they end up
sending each other barrages of stop signals. With the code shown above,
it is possible (though unlikely) to have two processes in a pipeline
`trade off' stops, so that you run:
% foo | bar
^Z
Stopped
% fg
Stopped
% fg
Stopped
% fg
Stopped
%
In each case either foo or bar `wins the race', stops both, then when you
foreground either foo or bar wins again, and stops both, and . . . .
This does not happen with only one process, though a different sort of
race can lead to two stops from two different signals, despite the
SIGCONT description below: If the process takes a SIGTSTP, and then
stops on a SIGSTOP during, e.g., the clean_tty() call above, it can
then send itself a SIGTSTP as soon as it is resumed.
The (4.3++) kernel implementation of signals is simply four bit vectors:
- signals currently pending (p_sig)
- signals currently held (p_sigmask)
- signals being caught (p_sigcatch)
- signals being ignored (p_sigignore)
Some of these fields exist only to optimise signal dispatching. The
most important thing is that a signal is delivered to a process with:
p->p_sig |= mask;
and a process takes a signal if:
(p->p_sig & ~p->p_sigmask) != 0
The signal it takes is the lowest-numbered one that is pending. When a
signal is taken the corresponding bit is removed from p->p_sig.
Typically, the same bit is set in p->p_sigmask, blocking further
delivery of that particular signal. (The new mask comes about from the
signal mask in the [4.2-style] sigvec or [POSIX-style] sigaction.)
When a SIGCONT signal is sent (not delivered, merely sent!), p->p_sig
has `stopsigmask' (the masks for SIGTSTP, SIGSTOP, SIGTTIN, and SIGTTOU)
removed, so one SIGCONT clears up to four stops. This can clear stops
that have never been taken.
--
In-Real-Life: Chris Torek, Lawrence Berkeley Lab EE div (+1 415 486 5427)
Berkeley, CA Domain: torek at ee.lbl.gov
More information about the Comp.unix.wizards
mailing list