1
0
mirror of https://github.com/gryf/wmaker.git synced 2025-12-20 21:08:08 +01:00

Fixed the buryChild thingie about the zombies problem.

This commit is contained in:
dan
2000-11-29 05:15:59 +00:00
parent 1a754844bb
commit bb6182f4f7

View File

@@ -25,6 +25,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <sys/wait.h>
#ifdef __FreeBSD__
@@ -381,35 +382,13 @@ buryChild(int foo)
int status;
/* R.I.P. */
/* SIGCHLD's are blocked while we are in this signal handler, and if 2 or
* more kids exit while we handle the exit of one child in this handler
* (ie, about at the same time), we will miss the SIGCHLD signals the
* other kids will send and will be left with zombies. Using a while loop
* tries to avoid this (or at least minimize the probability), by calling
* waitpid until there are no more exited kids that respond.
* I think there is still a small probability that a a SIGCHLD signal can
* arrive after we finished the while loop, but before we return.
* Passing SA_NODEFER to the SIGCHLD handler doesn't seem to help at all,
* though tha man page sais that using this flag should allow receival of
* other SIGCHLD signals while processing one. Why is this? -Dan
*
* There seem to be SA_NOCLDWAIT, but I'm not sure its available on all
* platforms, and its possible that even if it will prevent zombie
* generation, it may also prevent us from receiving the exit status
* of our kids (I'm not sure, because the man page doesn't state this
* clearly). -Dan
*
* Maybe the best way would be to forget about SA_NODEFER and do it the
* old way: unblock SIGCHLD immediately after we entered this handler,
* then call waitpid in a while loop to get the exit status of all kids
* that exited while SIGCHLD was blocked and we missed the signal.
* This way there is no way we can miss any kid, because the while loop
* takes care of signals that were missed before we reenabled SIGCHLD
* and after enabling the signal, we we start getting them even if we
* are in the signal handler itself. Only need to check if it doesn't
* have any problem with reentrancy, but I don't think so. -Dan
/* If 2 or more kids exit in a small time window, before this handler gets
* the chance to get invoked, the SIGCHLD signals will be merged and only
* one SIGCHLD signal will be sent to us. We use a while loop to get all
* exited child status because we can't count on the number of SIGCHLD
* signals to know exactly how many kids have exited. -Dan
*/
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
while ((pid=waitpid(-1, &status, WNOHANG))>0 || (pid<0 && errno==EINTR)) {
NotifyDeadProcess(pid, WEXITSTATUS(status));
/*
* Make sure that the kid will be buried even if there are
@@ -418,7 +397,7 @@ buryChild(int foo)
if (!WDelayedActionSet) {
WDelayedActionSet = 1;
WMAddIdleHandler(delayedAction, NULL);
}
}
}
}
@@ -824,9 +803,8 @@ StartUp(Bool defaultScreenOnly)
sigaction(SIGPIPE, &sig_action, NULL);
/* handle dead children */
/* Using SA_NODEFER doesn't seem to have any effect. Why? -Dan */
sig_action.sa_handler = buryChild;
sig_action.sa_flags = SA_NODEFER|SA_NOCLDSTOP|SA_RESTART;
sig_action.sa_flags = SA_NOCLDSTOP|SA_RESTART;
sigaction(SIGCHLD, &sig_action, NULL);
/* Now we unblock all signals, that may have been blocked by the parent