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.
This commit is contained in:
Roy Marples 2009-04-23 20:20:17 +00:00
parent 953b0b7435
commit 7dc9c39503

View File

@ -71,13 +71,9 @@
#define PREFIX_LOCK RC_SVCDIR "/prefix.lock" #define PREFIX_LOCK RC_SVCDIR "/prefix.lock"
/* usecs to wait while we poll the fifo */ #define WAIT_INTERVAL 20000000 /* usecs to poll the lock file */
#define WAIT_INTERVAL 20000000 #define WAIT_TIMEOUT 60 /* seconds until we timeout */
#define WARN_TIMEOUT 10 /* warn about this every N seconds */
/* max secs to wait until a service comes up */
#define WAIT_MAX 300
#define ONE_SECOND 1000000000
static const char *applet = NULL; static const char *applet = NULL;
static RC_STRINGLIST *applet_list = NULL; static RC_STRINGLIST *applet_list = NULL;
@ -480,12 +476,10 @@ static bool
svc_wait(const char *svc) svc_wait(const char *svc)
{ {
char file[PATH_MAX]; char file[PATH_MAX];
struct timespec ts;
int nloops = WAIT_MAX * (ONE_SECOND / WAIT_INTERVAL);
int sloops = (ONE_SECOND / WAIT_INTERVAL) * 5;
int fd; int fd;
bool forever = false; bool forever = false;
RC_STRINGLIST *keywords; RC_STRINGLIST *keywords;
struct timespec interval, timeout, warn;
/* Some services don't have a timeout, like fsck */ /* Some services don't have a timeout, like fsck */
keywords = rc_deptree_depend(deptree, svc, "keyword"); keywords = rc_deptree_depend(deptree, svc, "keyword");
@ -495,10 +489,14 @@ svc_wait(const char *svc)
snprintf(file, sizeof(file), RC_SVCDIR "/exclusive/%s", snprintf(file, sizeof(file), RC_SVCDIR "/exclusive/%s",
basename_c(svc)); 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); fd = open(file, O_RDONLY | O_NONBLOCK);
if (fd != -1) { if (fd != -1) {
if (flock(fd, LOCK_SH | LOCK_NB) == 0) { if (flock(fd, LOCK_SH | LOCK_NB) == 0) {
@ -510,23 +508,25 @@ svc_wait(const char *svc)
if (errno == ENOENT) if (errno == ENOENT)
return true; return true;
if (errno != EWOULDBLOCK) if (errno != EWOULDBLOCK)
eerrorx("%s: open `%s': %s", applet, file, strerror(errno)); eerrorx("%s: open `%s': %s", applet, file,
strerror(errno));
if (nanosleep(&ts, NULL) == -1) { if (nanosleep(&interval, NULL) == -1) {
if (errno != EINTR) if (errno != EINTR)
return false; return false;
} }
if (!forever) { if (!forever) {
nloops --; timespecsub(&timeout, &interval, &timeout);
if (timeout.tv_sec <= 0)
if (--sloops == 0) { return false;
ewarn("%s: waiting for %s", applet, svc); timespecsub(&warn, &interval, &warn);
sloops = (ONE_SECOND / WAIT_INTERVAL) * 5; 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; return false;
} }
@ -1178,6 +1178,12 @@ runscript(int argc, char **argv)
case_RC_COMMON_GETOPT 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 /* Save the IN_BACKGROUND env flag so it's ONLY passed to the service
that is being called and not any dependents */ that is being called and not any dependents */
if (getenv("IN_BACKGROUND")) { if (getenv("IN_BACKGROUND")) {