diff options
author | Stephen Gallagher <sgallagh@redhat.com> | 2010-12-01 12:07:28 -0500 |
---|---|---|
committer | Stephen Gallagher <sgallagh@redhat.com> | 2010-12-02 07:47:51 -0500 |
commit | c99f085747aabafc4a440b5bfd1d9a6bea995620 (patch) | |
tree | 696cdbc03e58c5f08fee2e63e1845e13b295e444 | |
parent | b892b95f0ba494a3e149164695ef58d79dd9fb0c (diff) | |
download | sssd-c99f085747aabafc4a440b5bfd1d9a6bea995620.tar.gz sssd-c99f085747aabafc4a440b5bfd1d9a6bea995620.tar.xz sssd-c99f085747aabafc4a440b5bfd1d9a6bea995620.zip |
Resend SIGTERM if child doesn't terminate
There is a race condition where if we send a SIGTERM before the
kernel has scheduled the child, it may be lost, and the child will
not terminate and will leave the monitor hung in wait().
This patch alters this behavior so that we will send the SIGTERM
again every 10ms and check the wait() in a nonblocking manner.
-rw-r--r-- | src/monitor/monitor.c | 64 |
1 files changed, 40 insertions, 24 deletions
diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c index 640d94adc..6eab66fc5 100644 --- a/src/monitor/monitor.c +++ b/src/monitor/monitor.c @@ -1176,6 +1176,8 @@ static void monitor_quit(struct tevent_context *ev, pid_t pid; int status; errno_t error; + int kret; + bool killed; DEBUG(8, ("Received shutdown command\n")); @@ -1189,35 +1191,49 @@ static void monitor_quit(struct tevent_context *ev, continue; } - DEBUG(1, ("Terminating [%s]\n", svc->name)); - kill(svc->pid, SIGTERM); - + killed = false; + DEBUG(1, ("Terminating [%s][%d]\n", svc->name, svc->pid)); do { errno = 0; - pid = waitpid(svc->pid, &status, 0); - if (pid == -1) { - /* An error occurred while waiting */ + kret = kill(svc->pid, SIGTERM); + if (kret < 0) { 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); + DEBUG(1, ("Couldn't kill [%s][%d]: [%s]\n", + svc->name, svc->pid, strerror(error))); + } + + do { + errno = 0; + pid = waitpid(svc->pid, &status, WNOHANG); + 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 if (pid != 0) { + 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); + } + killed = true; } + } while (error == EINTR); + if (!killed) { + /* Sleep 10ms and try again */ + usleep(10000); } - } while (error == EINTR); + } while (!killed); } #if HAVE_GETPGRP |