From df22628183a1717b2213b48bd94ea307d655e475 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Tue, 9 Oct 2018 07:14:33 +0200 Subject: [PATCH] Refactor end of bootstrap using new work queue helper Signed-off-by: Joachim Nilsson --- src/finit.c | 83 +++++++++++++++++++++++++++++++++++++-------------- src/service.c | 33 +++----------------- src/service.h | 2 +- 3 files changed, 65 insertions(+), 53 deletions(-) diff --git a/src/finit.c b/src/finit.c index fafc3b25..aaceae42 100644 --- a/src/finit.c +++ b/src/finit.c @@ -47,6 +47,7 @@ #include "tty.h" #include "util.h" #include "utmp-api.h" +#include "schedule.h" int runlevel = 0; /* Bootstrap 'S' */ int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */ @@ -63,6 +64,9 @@ char *runparts = NULL; uev_ctx_t *ctx = NULL; /* Main loop context */ svc_t *wdog = NULL; /* No watchdog by default */ +static int udev = 0; /* Runtime detection of udev */ + + /* * Show user configured banner before service bootstrap progress */ @@ -261,13 +265,61 @@ static void finalize(void) tty_runlevel(); } +/* + * Start cranking the big state machine + */ +static void crank_worker(void *unused) +{ + /* + * Initalize state machine and start all bootstrap tasks + * NOTE: no network available! + */ + sm_init(&sm); + sm_step(&sm); + + /* Debian has this little script to copy generated rules while the system was read-only */ + if (udev && fexist("/lib/udev/udev-finish")) + run_interactive("/lib/udev/udev-finish", "Finalizing udev"); +} + +/* + * Wait for system bootstrap to complete, all SVC_TYPE_RUNTASK must be + * allowed to complete their work in [S], or timeout, before we call + * finalize(), should not take more than 120 sec. + */ +static void final_worker(void *work) +{ + static int cnt = 120; + + _d("Step all services ..."); + service_step_all(SVC_TYPE_ANY); + + if (cnt-- > 0 && !service_completed()) { + _d("Not all bootstrap run/tasks have completed yet ... %d", cnt); + schedule_work(work); + return; + } + + if (cnt > 0) + _d("All run/task have completed, resuming bootstrap."); + else + _d("Timeout, resuming bootstrap."); + + finalize(); +} + int main(int argc, char* argv[]) { + struct wq crank = { + .cb = crank_worker + }; + struct wq final = { + .cb = final_worker, + .delay = 1000 + }; + uev_ctx_t loop; char *path; char cmd[256]; - int udev = 0; - uev_t timer; /* Bootstrap timer, on timeout call finalize() */ - uev_ctx_t loop; /* * finit/init/telinit client tool uses /dev/initctl pipe @@ -466,33 +518,18 @@ int main(int argc, char* argv[]) */ conf_monitor(&loop); - /* - * Initalize state machine and start all bootstrap tasks - * NOTE: no network available! - */ - sm_init(&sm); - sm_step(&sm); - - /* Debian has this little script to copy generated rules while the system was read-only */ - if (udev && fexist("/lib/udev/udev-finish")) - run_interactive("/lib/udev/udev-finish", "Finalizing udev"); - - /* Start new initctl API responder */ + _d("Starting initctl API responder ..."); api_init(&loop); umask(022); - /* Finalize bootstrap, allow service/run/tasks to complete */ - service_step_all(SVC_TYPE_ANY); + _d("Starting the big state machine ..."); + schedule_work(&crank); - /* - * Wait for all SVC_TYPE_RUNTASK to have completed their work in - * [S], or timeout, before calling finalize() - */ _d("Starting bootstrap finalize timer ..."); - uev_timer_init(&loop, &timer, service_bootstrap_cb, finalize, 1000, 1000); + schedule_work(&final); /* - * Enter main loop to monior /dev/initctl and services + * Enter main loop to monitor /dev/initctl and services */ _d("Entering main loop ..."); return uev_run(&loop, 0); diff --git a/src/service.c b/src/service.c index 5cff91d2..20889573 100644 --- a/src/service.c +++ b/src/service.c @@ -1243,21 +1243,20 @@ void service_runtask_clean(void) } /** - * service_runtask_completed - Have run/task completed in current runlevel - * @skip: Hardcoded list of conditions to skip + * service_completed - Have run/task completed in current runlevel * * This function checks if all run/task have run once in the current * runlevel. E.g., at bootstrap we must wait for these scripts or * programs to complete their run before switching to the configured * runlevel. * - * Setting @skip means skipping tasks with %HOOK_SVC_UP, %HOOK_SYSTEM_UP - * set in their condition mask. These tasks cannot run until finalize() + * All tasks with %HOOK_SVC_UP, %HOOK_SYSTEM_UP set in their condition + * mask are skipped. These tasks cannot run until finalize() * * Returns: * %TRUE(1) or %FALSE(0) */ -int service_runtask_completed(int skip) +int service_completed(void) { svc_t *svc, *iter = NULL; @@ -1284,30 +1283,6 @@ int service_runtask_completed(int skip) return 1; } -/* - * Wait for system bootstrap to complete, should not take more than 120 sec. - */ -void service_bootstrap_cb(uev_t *w, void *arg, int events) -{ - static int cnt = 120; - void (*finalize)(void) = arg; - - _d("Step all services ..."); - service_step_all(SVC_TYPE_ANY); - - _d("Checking completion of all run/task ... %d", cnt); - if (cnt-- > 0 && !service_runtask_completed(!runlevel)) - return; - - if (cnt > 0) - _d("All run/task have completed, resuming bootstrap."); - else - _d("Timeout, resuming bootstrap."); - cnt = 10; - uev_timer_stop(w); - finalize(); -} - /** * Local Variables: * indent-tabs-mode: t diff --git a/src/service.h b/src/service.h index 03fdd082..ee5f2a48 100644 --- a/src/service.h +++ b/src/service.h @@ -38,7 +38,7 @@ int service_step (svc_t *svc); void service_step_all (int types); void service_worker (void *unused); -void service_bootstrap_cb (uev_t *w, void *arg, int events); +int service_completed (void); #endif /* FINIT_SERVICE_H_ */