From 7dc9c39503ded408c34ba6cd96ebdab352fbb6a6 Mon Sep 17 00:00:00 2001 From: Roy Marples Date: Thu, 23 Apr 2009 20:20:17 +0000 Subject: [PATCH] Improve the service timeout code and reduce the timeout to 60 seconds. Don't process any dependencies when changing runlevels and called outside of RC otherwise we can deadlock. --- src/rc/runscript.c | 54 +++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/src/rc/runscript.c b/src/rc/runscript.c index a727ba07..8cfe5039 100644 --- a/src/rc/runscript.c +++ b/src/rc/runscript.c @@ -71,13 +71,9 @@ #define PREFIX_LOCK RC_SVCDIR "/prefix.lock" -/* usecs to wait while we poll the fifo */ -#define WAIT_INTERVAL 20000000 - -/* max secs to wait until a service comes up */ -#define WAIT_MAX 300 - -#define ONE_SECOND 1000000000 +#define WAIT_INTERVAL 20000000 /* usecs to poll the lock file */ +#define WAIT_TIMEOUT 60 /* seconds until we timeout */ +#define WARN_TIMEOUT 10 /* warn about this every N seconds */ static const char *applet = NULL; static RC_STRINGLIST *applet_list = NULL; @@ -480,12 +476,10 @@ static bool svc_wait(const char *svc) { char file[PATH_MAX]; - struct timespec ts; - int nloops = WAIT_MAX * (ONE_SECOND / WAIT_INTERVAL); - int sloops = (ONE_SECOND / WAIT_INTERVAL) * 5; int fd; bool forever = false; RC_STRINGLIST *keywords; + struct timespec interval, timeout, warn; /* Some services don't have a timeout, like fsck */ keywords = rc_deptree_depend(deptree, svc, "keyword"); @@ -495,10 +489,14 @@ svc_wait(const char *svc) snprintf(file, sizeof(file), RC_SVCDIR "/exclusive/%s", basename_c(svc)); - ts.tv_sec = 0; - ts.tv_nsec = WAIT_INTERVAL; - while (nloops) { + interval.tv_sec = 0; + interval.tv_nsec = WAIT_INTERVAL; + timeout.tv_sec = WAIT_TIMEOUT; + timeout.tv_nsec = 0; + warn.tv_sec = WARN_TIMEOUT; + warn.tv_nsec = 0; + for (;;) { fd = open(file, O_RDONLY | O_NONBLOCK); if (fd != -1) { if (flock(fd, LOCK_SH | LOCK_NB) == 0) { @@ -510,23 +508,25 @@ svc_wait(const char *svc) if (errno == ENOENT) return true; if (errno != EWOULDBLOCK) - eerrorx("%s: open `%s': %s", applet, file, strerror(errno)); - - if (nanosleep(&ts, NULL) == -1) { + eerrorx("%s: open `%s': %s", applet, file, + strerror(errno)); + if (nanosleep(&interval, NULL) == -1) { if (errno != EINTR) return false; } - if (!forever) { - nloops --; - - if (--sloops == 0) { - ewarn("%s: waiting for %s", applet, svc); - sloops = (ONE_SECOND / WAIT_INTERVAL) * 5; + timespecsub(&timeout, &interval, &timeout); + if (timeout.tv_sec <= 0) + return false; + timespecsub(&warn, &interval, &warn); + if (warn.tv_sec <= 0) { + ewarn("%s: waiting for %s (%zu)", applet, svc, + timeout.tv_sec); + warn.tv_sec = WARN_TIMEOUT; + warn.tv_nsec = 0; } } } - return false; } @@ -1178,6 +1178,12 @@ runscript(int argc, char **argv) case_RC_COMMON_GETOPT } + /* If we're changing runlevels and not called by rc then we cannot + work with any dependencies */ + if (deps && getenv("RC_PID") == NULL && + (rc_runlevel_starting() || rc_runlevel_stopping())) + deps = false; + /* Save the IN_BACKGROUND env flag so it's ONLY passed to the service that is being called and not any dependents */ if (getenv("IN_BACKGROUND")) { @@ -1272,7 +1278,7 @@ runscript(int argc, char **argv) RC_SERVICE_STARTED) svc_restart(deps); } else if (strcmp(optarg, "restart") == 0) { - svc_restart (deps); + svc_restart(deps); } else if (strcmp(optarg, "start") == 0) { svc_start(deps); } else if (strcmp(optarg, "stop") == 0) {