diff options
author | Stephen Gallagher <sgallagh@redhat.com> | 2010-11-11 09:04:22 -0500 |
---|---|---|
committer | Stephen Gallagher <sgallagh@redhat.com> | 2010-12-02 13:17:58 -0500 |
commit | 1b3b6f2e840ab6dfbfaa5d2b2e08709004a3bda2 (patch) | |
tree | c236defecaedfa60239f31fce769b93d142f77ff | |
parent | 4e6cc423196c67ee34701db5089920f1df0d4b00 (diff) | |
download | sssd2-1b3b6f2e840ab6dfbfaa5d2b2e08709004a3bda2.tar.gz sssd2-1b3b6f2e840ab6dfbfaa5d2b2e08709004a3bda2.tar.xz sssd2-1b3b6f2e840ab6dfbfaa5d2b2e08709004a3bda2.zip |
Wait for all children to exit
Previously, there was a race-condition where the monitor might
terminate before its children.
-rw-r--r-- | src/monitor/monitor.c | 63 |
1 files changed, 61 insertions, 2 deletions
diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c index 91bcb9a1..b5d93ed4 100644 --- a/src/monitor/monitor.c +++ b/src/monitor/monitor.c @@ -1145,16 +1145,75 @@ static void monitor_quit(struct tevent_context *ev, void *siginfo, void *private_data) { + struct mt_ctx *mt_ctx = talloc_get_type(private_data, struct mt_ctx); + struct mt_svc *svc; + pid_t pid; + int status; + errno_t error; + DEBUG(8, ("Received shutdown command\n")); - monitor_cleanup(); + + DEBUG(0, ("Monitor received %s: terminating children\n", + strsignal(signum))); + + /* Kill all of our known children manually */ + DLIST_FOR_EACH(svc, mt_ctx->svc_list) { + if (svc->pid == 0) { + /* The local provider has no PID */ + continue; + } + + DEBUG(1, ("Terminating [%s]\n", svc->name)); + kill(svc->pid, SIGTERM); + + do { + errno = 0; + pid = waitpid(svc->pid, &status, 0); + if (pid == -1) { + /* An error occurred while waiting */ + error = errno; + if (error != EINTR) { + DEBUG(0, ("[%d][%s] while waiting for [%s]\n", + error, strerror(error), svc->name)); + /* Forcibly kill this child */ + kill(svc->pid, SIGKILL); + break; + } + } else { + error = 0; + if WIFEXITED(status) { + DEBUG(1, ("Child [%s] exited gracefully\n", svc->name)); + } else if WIFSIGNALED(status) { + DEBUG(1, ("Child [%s] terminated with a signal\n", svc->name)); + } else { + DEBUG(0, ("Child [%s] did not exit cleanly\n", svc->name)); + /* Forcibly kill this child */ + kill(svc->pid, SIGKILL); + } + } + } while (error == EINTR); + } #if HAVE_GETPGRP + /* Kill any remaining children in our process group, just in case + * we have any leftover children we don't expect. For example, if + * a krb5_child or ldap_child is running at the same moment. + */ + error = 0; if (getpgrp() == getpid()) { - DEBUG(0,("%s: killing children\n", strsignal(signum))); kill(-getpgrp(), SIGTERM); + do { + errno = 0; + pid = waitpid(0, &status, 0); + if (pid == -1) { + error = errno; + } + } while (error == EINTR || pid > 0); } #endif + monitor_cleanup(); + exit(0); } |