Path: utzoo!mnetor!tmsoft!torsqnt!news-server.csri.toronto.edu!cs.utexas.edu!swrinde!zaphod.mps.ohio-state.edu!magnus.ircc.ohio-state.edu!tut.cis.ohio-state.edu!ucbvax!dog.ee.lbl.gov!elf.ee.lbl.gov!torek From: torek@elf.ee.lbl.gov (Chris Torek) Newsgroups: comp.unix.questions Subject: Re: how to suspend a process Message-ID: <9999@dog.ee.lbl.gov> Date: 18 Feb 91 09:51:17 GMT References: <7016@alpha.cam.nist.gov> <121503@uunet.UU.NET> Reply-To: torek@elf.ee.lbl.gov (Chris Torek) Organization: Lawrence Berkeley Laboratory, Berkeley Lines: 70 X-Local-Date: Mon, 18 Feb 91 01:51:17 PST In article <121503@uunet.UU.NET> rbj@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@ee.lbl.gov