summaryrefslogtreecommitdiff
path: root/src/monitor
diff options
context:
space:
mode:
authorStephen Gallagher <sgallagh@redhat.com>2010-11-11 09:04:22 -0500
committerStephen Gallagher <sgallagh@redhat.com>2010-11-18 08:34:55 -0500
commitb853b135b9dfa315973faff706eb32aa36b5934a (patch)
treef4be029c45a15c456153a9d485dd5bb407eb0b80 /src/monitor
parentc7bca19b94bd48d0088e5a8002946b345b6adcc1 (diff)
downloadsssd-b853b135b9dfa315973faff706eb32aa36b5934a.tar.gz
sssd-b853b135b9dfa315973faff706eb32aa36b5934a.tar.bz2
sssd-b853b135b9dfa315973faff706eb32aa36b5934a.zip
Wait for all children to exit
Previously, there was a race-condition where the monitor might terminate before its children.
Diffstat (limited to 'src/monitor')
-rw-r--r--src/monitor/monitor.c63
1 files changed, 61 insertions, 2 deletions
diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
index 6479f7a9..98b671b2 100644
--- a/src/monitor/monitor.c
+++ b/src/monitor/monitor.c
@@ -1171,16 +1171,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);
}