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