aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2009-04-23 20:20:17 +0000
committerRoy Marples <roy@marples.name>2009-04-23 20:20:17 +0000
commit7dc9c39503ded408c34ba6cd96ebdab352fbb6a6 (patch)
tree32ef5df0e73ff89cdceeec54439da091625092c7
parent953b0b74357d28a1ec28ca13fbdeaa126fa2bbaa (diff)
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.
-rw-r--r--src/rc/runscript.c54
1 files 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) {