summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Gallagher <sgallagh@redhat.com>2010-12-01 12:07:28 -0500
committerStephen Gallagher <sgallagh@redhat.com>2010-12-02 13:17:58 -0500
commit499db30832152fbd7050fd74036ed85deb669860 (patch)
treeb1aa34dd26d366c23bf201328e42b3931fc3f248
parent1b3b6f2e840ab6dfbfaa5d2b2e08709004a3bda2 (diff)
downloadsssd-499db30832152fbd7050fd74036ed85deb669860.tar.gz
sssd-499db30832152fbd7050fd74036ed85deb669860.tar.xz
sssd-499db30832152fbd7050fd74036ed85deb669860.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.c64
1 files changed, 40 insertions, 24 deletions
diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
index b5d93ed4d..ac55d7c33 100644
--- a/src/monitor/monitor.c
+++ b/src/monitor/monitor.c
@@ -1150,6 +1150,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"));
@@ -1163,35 +1165,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