Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!sdd.hp.com!caen!hellgate.utah.edu!dog.ee.lbl.gov!elf.ee.lbl.gov!torek From: torek@elf.ee.lbl.gov (Chris Torek) Newsgroups: comp.unix.wizards Subject: Re: SIGCONT occurs after a SIGTERM Message-ID: <10114@dog.ee.lbl.gov> Date: 21 Feb 91 16:17:47 GMT References: <67880001@hpcupt1.cup.hp.com> <2519@inews.intel.com> <10007@dog.ee.lbl.gov> <2588@inews.intel.com> Reply-To: torek@elf.ee.lbl.gov (Chris Torek) Organization: Lawrence Berkeley Laboratory, Berkeley Lines: 102 X-Local-Date: Thu, 21 Feb 91 08:17:48 PST >In article <10007@dog.ee.lbl.gov> I wrote: >>Signals are not queued. In article <2588@inews.intel.com> bhoughto@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@ee.lbl.gov Brought to you by Super Global Mega Corp .com