From 87f9b94b42176131d1694043c214d474667475ae Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Thu, 19 Nov 2015 19:29:13 +0100 Subject: [PATCH] Call HOOK_SVC_RECONF only when all processes have been stopped This patch fixes a race condition when doing an ordered RELOAD and STOP event sequence. For services that shall be stopped it is imperative that we wait for them to be colleced by the `service_monitor()`, so that we know they have really been stopped, before calling HOOK_SVC_RECONF. The latter is a promise to external services that all services have been indeed stopped. Signed-off-by: Joachim Nilsson --- service.c | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/service.c b/service.c index 87862922..2a279018 100644 --- a/service.c +++ b/service.c @@ -41,6 +41,8 @@ #define RESPAWN_MAX 10 /* Prevent endless respawn of faulty services. */ +static int dyn_stop_cnt = 0; + static int is_norespawn (void); static void restart_lost_procs (void); static void svc_dance (svc_t *svc); @@ -364,6 +366,26 @@ void service_start_dynamic(void) svc_clean_dynamic(service_unregister); } +/* + * Unless there are services we must collect first (wait for + * them to stop), we can call HOOK_SVC_RECONF here. + */ +static int service_stop_done(svc_t *svc) +{ + if (svc && !svc_is_changed(svc)) + return 0; + + if (svc && dyn_stop_cnt) + dyn_stop_cnt--; + + if (!dyn_stop_cnt) { + _d("All disabled/removed services have been stoppped, calling reconf hooks ..."); + plugin_run_hooks(HOOK_SVC_RECONF); /* Reconfigure HW/VLANs/etc here */ + } + + return 1; +} + /** * service_stop_dynamic - Stop disabled/removed dynamic services */ @@ -373,12 +395,14 @@ void service_stop_dynamic(void) _d("Stopping disabled/removed services ..."); for (svc = svc_dynamic_iterator(1); svc; svc = svc_dynamic_iterator(0)) { - if (svc_is_changed(svc)) + if (svc_is_changed(svc)) { + dyn_stop_cnt++; service_stop(svc); + } } - _d("All disabled/removed services have been stoppped, calling reconf hooks ..."); - plugin_run_hooks(HOOK_SVC_RECONF); /* Reconfigure HW/VLANs/etc here */ + /* Check if we need to collect any services before calling user HOOK */ + service_stop_done(NULL); } /* stop + start @@ -809,6 +833,10 @@ void service_monitor(pid_t lost) /* No longer running, update books. */ svc->pid = 0; + /* Check if we're still collecting stopped dynamic services */ + if (service_stop_done(svc)) + break; + if (sig_stopped()) { _e("Stopped, not respawning killed processes."); break;