Merge changes Ib54f39fd,I7e36edd8

* changes:
  init: Retain traditional restart behavior for critical and oneshot services.
  init: Safely restart services to avoid race conditions.
This commit is contained in:
Colin Cross 2013-06-24 22:23:32 +00:00 committed by Gerrit Code Review
commit 83ada447ae
4 changed files with 38 additions and 15 deletions

View file

@ -590,8 +590,7 @@ int do_restart(int nargs, char **args)
struct service *svc; struct service *svc;
svc = service_find_by_name(args[1]); svc = service_find_by_name(args[1]);
if (svc) { if (svc) {
service_stop(svc); service_restart(svc);
service_start(svc, NULL);
} }
return 0; return 0;
} }

View file

@ -164,7 +164,7 @@ void service_start(struct service *svc, const char *dynamic_args)
* state and immediately takes it out of the restarting * state and immediately takes it out of the restarting
* state if it was in there * state if it was in there
*/ */
svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET)); svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART));
svc->time_started = 0; svc->time_started = 0;
/* running processes require no additional work -- if /* running processes require no additional work -- if
@ -359,15 +359,14 @@ void service_start(struct service *svc, const char *dynamic_args)
notify_service_state(svc->name, "running"); notify_service_state(svc->name, "running");
} }
/* The how field should be either SVC_DISABLED or SVC_RESET */ /* The how field should be either SVC_DISABLED, SVC_RESET, or SVC_RESTART */
static void service_stop_or_reset(struct service *svc, int how) static void service_stop_or_reset(struct service *svc, int how)
{ {
/* we are no longer running, nor should we /* The service is still SVC_RUNNING until its process exits, but if it has
* attempt to restart * already exited it shoudn't attempt a restart yet. */
*/ svc->flags &= (~SVC_RESTARTING);
svc->flags &= (~(SVC_RUNNING|SVC_RESTARTING));
if ((how != SVC_DISABLED) && (how != SVC_RESET)) { if ((how != SVC_DISABLED) && (how != SVC_RESET) && (how != SVC_RESTART)) {
/* Hrm, an illegal flag. Default to SVC_DISABLED */ /* Hrm, an illegal flag. Default to SVC_DISABLED */
how = SVC_DISABLED; how = SVC_DISABLED;
} }
@ -399,6 +398,17 @@ void service_stop(struct service *svc)
service_stop_or_reset(svc, SVC_DISABLED); service_stop_or_reset(svc, SVC_DISABLED);
} }
void service_restart(struct service *svc)
{
if (svc->flags & SVC_RUNNING) {
/* Stop, wait, then start the service. */
service_stop_or_reset(svc, SVC_RESTART);
} else if (!(svc->flags & SVC_RESTARTING)) {
/* Just start the service since it's not running. */
service_start(svc, NULL);
} /* else: Service is restarting anyways. */
}
void property_changed(const char *name, const char *value) void property_changed(const char *name, const char *value)
{ {
if (property_triggers_enabled) if (property_triggers_enabled)
@ -467,6 +477,17 @@ static void msg_stop(const char *name)
} }
} }
static void msg_restart(const char *name)
{
struct service *svc = service_find_by_name(name);
if (svc) {
service_restart(svc);
} else {
ERROR("no such service '%s'\n", name);
}
}
void handle_control_message(const char *msg, const char *arg) void handle_control_message(const char *msg, const char *arg)
{ {
if (!strcmp(msg,"start")) { if (!strcmp(msg,"start")) {
@ -474,8 +495,7 @@ void handle_control_message(const char *msg, const char *arg)
} else if (!strcmp(msg,"stop")) { } else if (!strcmp(msg,"stop")) {
msg_stop(arg); msg_stop(arg);
} else if (!strcmp(msg,"restart")) { } else if (!strcmp(msg,"restart")) {
msg_stop(arg); msg_restart(arg);
msg_start(arg);
} else { } else {
ERROR("unknown control msg '%s'\n", msg); ERROR("unknown control msg '%s'\n", msg);
} }

View file

@ -72,6 +72,7 @@ struct svcenvinfo {
#define SVC_RESET 0x40 /* Use when stopping a process, but not disabling #define SVC_RESET 0x40 /* Use when stopping a process, but not disabling
so it can be restarted with its class */ so it can be restarted with its class */
#define SVC_RC_DISABLED 0x80 /* Remember if the disabled flag was set in the rc script */ #define SVC_RC_DISABLED 0x80 /* Remember if the disabled flag was set in the rc script */
#define SVC_RESTART 0x100 /* Use to safely restart (stop, wait, start) a service */
#define NR_SVC_SUPP_GIDS 12 /* twelve supplementary groups */ #define NR_SVC_SUPP_GIDS 12 /* twelve supplementary groups */
@ -127,6 +128,7 @@ void service_for_each_flags(unsigned matchflags,
void (*func)(struct service *svc)); void (*func)(struct service *svc));
void service_stop(struct service *svc); void service_stop(struct service *svc);
void service_reset(struct service *svc); void service_reset(struct service *svc);
void service_restart(struct service *svc);
void service_start(struct service *svc, const char *dynamic_args); void service_start(struct service *svc, const char *dynamic_args);
void property_changed(const char *name, const char *value); void property_changed(const char *name, const char *value);

View file

@ -63,7 +63,7 @@ static int wait_for_one_process(int block)
NOTICE("process '%s', pid %d exited\n", svc->name, pid); NOTICE("process '%s', pid %d exited\n", svc->name, pid);
if (!(svc->flags & SVC_ONESHOT)) { if (!(svc->flags & SVC_ONESHOT) || (svc->flags & SVC_RESTART)) {
kill(-pid, SIGKILL); kill(-pid, SIGKILL);
NOTICE("process '%s' killing any children in process group\n", svc->name); NOTICE("process '%s' killing any children in process group\n", svc->name);
} }
@ -78,8 +78,9 @@ static int wait_for_one_process(int block)
svc->pid = 0; svc->pid = 0;
svc->flags &= (~SVC_RUNNING); svc->flags &= (~SVC_RUNNING);
/* oneshot processes go into the disabled state on exit */ /* oneshot processes go into the disabled state on exit,
if (svc->flags & SVC_ONESHOT) { * except when manually restarted. */
if ((svc->flags & SVC_ONESHOT) && !(svc->flags & SVC_RESTART)) {
svc->flags |= SVC_DISABLED; svc->flags |= SVC_DISABLED;
} }
@ -90,7 +91,7 @@ static int wait_for_one_process(int block)
} }
now = gettime(); now = gettime();
if (svc->flags & SVC_CRITICAL) { if ((svc->flags & SVC_CRITICAL) && !(svc->flags & SVC_RESTART)) {
if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) { if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {
if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) { if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {
ERROR("critical process '%s' exited %d times in %d minutes; " ERROR("critical process '%s' exited %d times in %d minutes; "
@ -105,6 +106,7 @@ static int wait_for_one_process(int block)
} }
} }
svc->flags &= (~SVC_RESTART);
svc->flags |= SVC_RESTARTING; svc->flags |= SVC_RESTARTING;
/* Execute all onrestart commands for this service. */ /* Execute all onrestart commands for this service. */