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:
parent
953b0b7435
commit
7dc9c39503
@ -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")) {
|
||||||
@ -1272,7 +1278,7 @@ runscript(int argc, char **argv)
|
|||||||
RC_SERVICE_STARTED)
|
RC_SERVICE_STARTED)
|
||||||
svc_restart(deps);
|
svc_restart(deps);
|
||||||
} else if (strcmp(optarg, "restart") == 0) {
|
} else if (strcmp(optarg, "restart") == 0) {
|
||||||
svc_restart (deps);
|
svc_restart(deps);
|
||||||
} else if (strcmp(optarg, "start") == 0) {
|
} else if (strcmp(optarg, "start") == 0) {
|
||||||
svc_start(deps);
|
svc_start(deps);
|
||||||
} else if (strcmp(optarg, "stop") == 0) {
|
} else if (strcmp(optarg, "stop") == 0) {
|
||||||
|
Loading…
Reference in New Issue
Block a user