how to suspend a process

Chris Torek torek at elf.ee.lbl.gov
Mon Feb 18 20:51:17 AEST 1991


In article <121503 at uunet.UU.NET> rbj at uunet.UU.NET (Root Boy Jim) writes:
>In your handler, you send yourself a SIGSTOP, which you cannot catch.
>You could also unregister your handler, then send a SIGTSTP.

The second is `better' aesthetically.

Handling stops correctly is actually quite tricky.  When you receive
a TSTP signal you may assume that all other processes in your process
group have also received one.  You must therefore not send a second
TSTP to everyone (kill(0, SIGTSTP)) but rather only to yourself
(kill(getpid(), SIGTSTP)).

To make the stop `atomic' (i.e., to prevent users with itchy ^Z fingers
from stopping you while you are setting up to be stopped) you should
(a) be using the `Berkeley signal' mechanism (likely to be available,
if not the default, given that you have SIGTSTP in the first place);
(b) use code of the form:

	stop_handler()
	{
		sigmask_t omask;

		... do cleanup operations ...
		/*
		 * SIGTSTP is currently blocked.
		 * To stop exactly once, send another TSTP in case
		 * none are pending.  (If one is pending, the kill()
		 * will still leave exactly one pending.)  Then
		 * atomically lower the mask and wait for the signal.
		 *
		 * Alternatively, we could use the sequence
		 *	sigsetmask(omask & ~sigmask(SIGTSTP));
		 *	sigsetmask(omask);
		 * which would let the signal in (thus stopping)
		 * then block the signal once we are resumed, but
		 * one call to sigpause is more efficient.
		 */
		omask = sigblock(0);
		(void) kill(getpid(), SIGTSTP);
		(void) sigpause(omask & ~sigmask(SIGTSTP));
		... do setup again ...
	}

The equivalent sequence of POSIX signal calls is:

	sigset_t none, tmp;

	(void) sigemptyset(&none);
	(void) sigprocmask(SIG_BLOCK, &none, &tmp);
	(void) sigdelset(&tmp, SIGTSTP);
	(void) sigsuspend(&tmp);

If the reason you are catching signals is that you modify a tty state
(e.g., use CBREAK/not-ICANON mode), you should be careful to pick up
the new state after the stop.  A number of programs, including `vi',
assume that the state they got when the first started is still in
effect, and the sequence:

	% stty erase ^h
	% vi
	:stop
	% stty erase ^_
	% fg
	:q
	%

leaves erase set to ^H rather than ^_.
-- 
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.questions mailing list