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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user