Messages in this thread |  | | Date | Mon, 17 Jun 1996 15:39:31 -0600 (MDT) | From | Marc Aurele La France <> | Subject | Re: On SIGCHLD signal semantics |
| |
On Fri, 14 Jun 1996, Theodore Y. Ts'o wrote:
> Why are we trying to work so hard to accomodate broken programs? Broken > programs should be fixed, not coddled by adding needless complexity into > the kernel.
I'll recap to clear up the misunderstanding that definitely exists here. Throughout this, I'll assume no signals other than SIGCHLD are involved. I'm not proposing behavioural changes when this assumption is broken (SIGSTOP'ped children, etc), so making this assumption will reduce confusion. I'll also assume a parent process has remaining children (zombies or not), otherwise a wait syscall always fails with ECHILD.
Currently, Linux's SIGCHLD signal semantics are
(a) When the parent has set or inherited a SIGCHLD signal handler other than SIG_IGN: - A wait syscall will suspend the parent, if necessary, until one of its children exits (i.e. becomes a zombie). The first zombie found is then cleaned out and its pid is returned to the parent. - The kernel does not clean out any other of the parent's zombies.
(b) When the parent has explicitly set its SIGCHLD signal handler to SIG_IGN: - A wait syscall will suspend the parent until one of its children exits. When the parent is woken up, the resulting zombie is cleaned out and its pid is returned to the parent. - The kernel cleans out any zombies the parent leaves behind.
(c) When the parent has inherited a SIGCHLD signal handler of SIG_IGN: Same as (b).
There are a few problems with this.
First, applications that set their SIGCHLD handler to SIG_IGN are not inherently broken. They are simply expecting System V semantics. But they are only getting a partial implementation of these semantics. Worse, a wait syscall will return a different result depending on whether or not a child exits before the parent issues the syscall.
To fix this, new definitions are needed. A dead zombie is a process that exits while its parent's SIGCHLD signal handler is SIG_IGN. A live zombie is a process that exits while its parent's SIGCHLD signal handler is *not* SIG_IGN. Now, the above (b) can be replaced with
(b) When the parent has explicitly set its SIGCHLD signal handler to SIG_IGN: - A wait syscall will clean out any remaining dead zombies (this is just an optimization). The syscall will then do one of two things. If any live zombies remain, the syscall will clean out the first one it finds and return its pid to the parent. Otherwise, the parent will be suspended, if necessary, until *all* its remaining children exit. As each child exits, the resulting dead zombie is cleaned out. When no children remain, the syscall will fail with ECHILD. - The kernel cleans out any dead zombies the parent leaves behind.
This change to (b) results in System V semantics. Better yet, an application must explicitly request wait's broken behaviour by spawning children *before* setting its SIGCHLD signal handler to SIG_IGN.
Now, on to the second problem...
Applications that do a wait syscall with an inherited SIGCHLD signal handler are not inherently broken. They are simply expecting BSD semantics. But they also are only getting a partial implementation. If they are unlucky enough to inherit SIG_IGN as their SIGCHLD signal handler, they will randomly fail. Indeed, the only difference the above change to (b) introduces to this scenario is to make this failure certain. The problem here is one of error localization and of process independence. Here, the kernel is penalizing the wrong programme, letting the real culprit (which could be a few fork()'s away up the process tree) continue scot-free.
The solution to this second problem involves slightly redefining live and dead zombies. A dead zombie is a process that exits while its parent's SIGCHLD handler is *explicitly* set to SIG_IGN. A live zombie is any other zombie. Now, (b) reads the same as the above System V replacement for it (keeping the new definitions in mind) and (c) becomes
(c) When the parent has inherited a SIGCHLD signal handler of SIG_IGN: Same as (a), instead of (b).
This gives POSIX compliance in all three (a), (b) and (c), BSD compatibility in cases (a) and (c), System V compatibility in cases (a) and (b). BSD compatibility in case (b) is a non-issue because in BSD SIGCHLD signal semantics, SIG_IGN is the same as SIG_DFL, and therefore there is no real reason for a BSD programme to explicitly set its SIGCHLD signal handler to SIG_IGN. System V compatibility in case (c) depends on whether or not one accepts my previously derived contention that the X/Open specification leaves case (c) as unspecified. If this contention doesn't hold water, one must still decide between the X/Open spec and an implementation that runs BSD applications properly, in addition to System V applications. In my view, the spec loses, hands down.
Note that none of the above affects other aspects of having SIG_IGN as a SIGCHLD signal handler (signal() return values, etc.). As to the perceived complexity of the above, one need only document that a programme gets BSD semantics until it sets its SIGCHLD handler, at which point it will have to deal with System V semantics.
One open question remains, and that is the advisability of causing child processes to inherit SIG_IGN as their SIGCHLD signal handler (i.e. to do an exec* syscall while ignoring child processes). Although above I characterize programmes that implement such behaviour as "culprits", I do not, at this time, know if they are in the wrong. I have yet to see a compelling case for or against this practice. I therefore leave it alone (for now).
Your witness, Counsellor...
Marc.
+----------------------------------+-----------------------------------+ | Marc Aurele La France | work: 1-403-492-9310 | | Computing and Network Services | fax: 1-403-492-1729 | | 352 General Services Building | email: tsi@ualberta.ca | | University of Alberta +-----------------------------------+ | Edmonton, Alberta | | | T6G 2H1 | Standard disclaimers apply | | CANADA | | +----------------------------------+-----------------------------------+
|  |