diff --git a/service.c b/service.c index 5e22e27f..09360376 100644 --- a/service.c +++ b/service.c @@ -42,8 +42,6 @@ #define RESPAWN_MAX 10 /* Prevent endless respawn of faulty services. */ -static int in_teardown = 0, in_dyn_teardown = 0; - #ifndef INETD_DISABLED static svc_t *find_inetd_svc (char *path, char *service, char *proto); #endif @@ -332,19 +330,6 @@ static int service_restart(svc_t *svc) return err; } -/** - * service_reload_dynamic_finish - Finish dynamic service reload - * - * Second stage of dynamic reload. Called either directly from first - * stage if no services had to be stopped, or later from - * service_monitor once all stopped services have been collected. - */ -static void service_reload_dynamic_finish(void) -{ - in_dyn_teardown = 0; - sm_step(&sm); -} - /** * service_reload_dynamic - Called on SIGHUP, 'init q' or 'initctl reload' * @@ -354,24 +339,10 @@ static void service_reload_dynamic_finish(void) */ void service_reload_dynamic(void) { - in_dyn_teardown = 1; sm_set_reload(&sm); sm_step(&sm); } -/** - * service_runlevel_finish - Finish runlevel change - * - * Second stage of runlevel change. Called either directly from first - * stage if no services had to be stopped, or later from - * service_monitor once all stopped services have been collected. - */ -static void service_runlevel_finish(void) -{ - in_teardown = 0; - sm_step(&sm); -} - /** * service_runlevel - Change to a new runlevel * @newlevel: New runlevel to activate @@ -381,7 +352,6 @@ static void service_runlevel_finish(void) */ void service_runlevel(int newlevel) { - in_teardown = 1; sm_set_runlevel(&sm, newlevel); sm_step(&sm); } @@ -627,29 +597,6 @@ void service_unregister(svc_t *svc) svc_del(svc); } -/** - * service_teardown_finish - Complete runlevel change or dynamic reload - * - * If any runlevel change or dynamic service reload is in progress and - * all services that had to be stopped have been collected, run the - * corresponding second stage. - */ -static void service_teardown_finish(void) -{ - if (!(in_teardown || in_dyn_teardown)) - return; - - if (!service_stop_is_done()) - return; - - if (in_teardown) - service_runlevel_finish(); - - if (in_dyn_teardown) - service_reload_dynamic_finish(); -} - - void service_monitor(pid_t lost) { svc_t *svc; @@ -676,8 +623,7 @@ void service_monitor(pid_t lost) svc->pid = 0; service_step(svc); - /* Check if we're still collecting stopped dynamic services */ - service_teardown_finish(); + sm_step(&sm); } static void svc_set_state(svc_t *svc, svc_state_t new) @@ -757,6 +703,10 @@ restart: break; } + /* wait until all processes has been stopped before continuing... */ + if (sm_is_in_teardown(&sm)) + break; + err = service_start(svc); if (err) { (*restart_counter)++; @@ -813,6 +763,9 @@ restart: case COND_ON: if (svc_is_changed(svc)) { if (svc->sighup) { + /* wait until all processes has been stopped before continuing... */ + if (sm_is_in_teardown(&sm)) + break; service_restart(svc); } else { service_stop(svc); diff --git a/sm.c b/sm.c index 222f9a92..288473cf 100644 --- a/sm.c +++ b/sm.c @@ -40,19 +40,10 @@ void sm_init(sm_t *sm) sm->state = SM_BOOTSTRAP_STATE; sm->newlevel = -1; sm->reload = 0; + sm->in_teardown = 0; } -void sm_set_runlevel(sm_t *sm, int newlevel) -{ - sm->newlevel = newlevel; -} - -void sm_set_reload(sm_t *sm) -{ - sm->reload = 1; -} - -char *sm_status(sm_t *sm) +static char *sm_status(sm_t *sm) { switch (sm->state) { case SM_BOOTSTRAP_STATE: @@ -72,6 +63,21 @@ char *sm_status(sm_t *sm) } } +void sm_set_runlevel(sm_t *sm, int newlevel) +{ + sm->newlevel = newlevel; +} + +void sm_set_reload(sm_t *sm) +{ + sm->reload = 1; +} + +int sm_is_in_teardown(sm_t *sm) +{ + return sm->in_teardown; +} + void sm_step(sm_t *sm) { sm_state_t old_state; @@ -117,6 +123,7 @@ restart: conf_reload_dynamic(); _d("Stopping services services not allowed in new runlevel ..."); + sm->in_teardown = 1; service_step_all(SVC_TYPE_ANY); sm->state = SM_RUNLEVEL_WAIT_STATE; @@ -133,6 +140,7 @@ restart: plugin_run_hooks(HOOK_RUNLEVEL_CHANGE); /* Reconfigure HW/VLANs/etc here */ _d("Starting services services new to this runlevel ..."); + sm->in_teardown = 0; service_step_all(SVC_TYPE_ANY); /* Cleanup stale services */ @@ -168,6 +176,7 @@ restart: /* Then, mark all affected service conditions as in-flux and * let all affected services move to WAITING/HALTED */ _d("Stopping services services not allowed after reconf ..."); + sm->in_teardown = 1; cond_reload(); service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_INETD); @@ -180,6 +189,7 @@ restart: if (!service_stop_is_done()) break; + sm->in_teardown = 0; /* Cleanup stale services */ svc_clean_dynamic(service_unregister); diff --git a/sm.h b/sm.h index 9f158ffa..9bb8d584 100644 --- a/sm.h +++ b/sm.h @@ -25,24 +25,26 @@ #define FINIT_SM_H_ typedef enum { - SM_BOOTSTRAP_STATE = 0, - SM_RUNNING_STATE, - SM_RUNLEVEL_CHANGE_STATE, - SM_RUNLEVEL_WAIT_STATE, - SM_RELOAD_CHANGE_STATE, - SM_RELOAD_WAIT_STATE, + SM_BOOTSTRAP_STATE = 0, /* Init state, bootstrap services */ + SM_RUNNING_STATE, /* Normal state, services running */ + SM_RUNLEVEL_CHANGE_STATE, /* A runlevel change has occured */ + SM_RUNLEVEL_WAIT_STATE, /* Waiting for all stopped runlevel processes to be halted */ + SM_RELOAD_CHANGE_STATE, /* A reload event has occured */ + SM_RELOAD_WAIT_STATE, /* Waiting for all stopped reload processes to be halted */ } sm_state_t; typedef struct sm { - sm_state_t state; - int newlevel; - int reload; + sm_state_t state; /* Running, Changed, Waiting, ... */ + int newlevel; /* Set on runlevel change to new runlevel, -1 if not change */ + int reload; /* Set on reload event, else 0 */ + int in_teardown; /* Set when waiting for all processes to be halted */ } sm_t; void sm_init(sm_t *sm); void sm_step(sm_t *sm); void sm_set_runlevel(sm_t *sm, int newlevel); void sm_set_reload(sm_t *sm); +int sm_is_in_teardown(sm_t *sm); #endif /* FINIT_SM_H_ */