diff --git a/src/sig.c b/src/sig.c index 43b0d80a..b643d63f 100644 --- a/src/sig.c +++ b/src/sig.c @@ -71,6 +71,7 @@ #include #include /* strerror() */ +#include #include #include #ifdef _LIBITE_LITE @@ -172,7 +173,7 @@ void unmount_regular(void); * * https://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons/ */ -void do_kill(int signo) +void do_iterate_proc(int (*callback)(int, int *), int *context) { DIR *dirp; @@ -191,6 +192,8 @@ void do_kill(int signo) pid = atoi(d->d_name); if (!pid) continue; + if (pid == 1) + continue; snprintf(file, sizeof(file), "/proc/%s/cmdline", d->d_name); fp = fopen(file, "r"); @@ -203,7 +206,10 @@ void do_kill(int signo) else if (file[0] == '@') _d("Skipping %s ...", &file[1]); else - kill(pid, signo); + if (callback(pid, context)) { + print(0, "PID %d is still alive (%s)", pid, file); + break; + } } fclose(fp); } @@ -211,8 +217,51 @@ void do_kill(int signo) } } +static int kill_callback(int pid, int *context) +{ + kill(pid, (int)context); + return 0; +} + +static int status_callback(int pid, int *context) +{ + *context = 1; + return 1; +} + +/* return value: + * 1 - at least one process remaining + * 0 - no processes remaining + */ +static int do_wait(int secs) +{ + int has_proc; + int tmo = 250000; + int iterations = secs*1000*1000/tmo; + + do { + do_usleep(tmo); + while (waitpid(-1, NULL, WNOHANG) > 0) + ; + has_proc = 0; + iterations--; + do_iterate_proc(status_callback, &has_proc); + } + while (has_proc && iterations > 0); + + return has_proc; +} + void do_shutdown(shutop_t op) { + struct sched_param sched_param = { .sched_priority = 99 }; + + /* + * On a PREEMPT-RT system, Finit must run as the highest prioritized + * RT process to ensure it completes the shutdown sequence. + */ + sched_setscheduler(1, SCHED_RR, &sched_param); + if (sdown) run_interactive(sdown, "Calling shutdown hook: %s", sdown); @@ -223,9 +272,10 @@ void do_shutdown(shutop_t op) * Tell remaining non-monitored processes to exit, give them * time to exit gracefully, 2 sec was customary, we go for 1. */ - do_kill(SIGTERM); - do_sleep(1); - do_kill(SIGKILL); + do_iterate_proc(kill_callback, (int*)SIGTERM); + if (do_wait(1)) { + do_iterate_proc(kill_callback, (int*)SIGKILL); + } /* Exit plugins and API gracefully */ plugin_exit(); diff --git a/src/util.c b/src/util.c index f612a981..1a6b353a 100644 --- a/src/util.c +++ b/src/util.c @@ -297,6 +297,20 @@ void do_sleep(unsigned int sec) ; } +void do_usleep(unsigned int usec) +{ + struct timespec deadline; + + clock_gettime(CLOCK_MONOTONIC, &deadline); + + deadline.tv_nsec += usec * 1000; + deadline.tv_sec += deadline.tv_nsec / 1000000000; + deadline.tv_nsec = deadline.tv_nsec % 1000000000; + + while (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &deadline, NULL) != 0 && errno == EINTR) + ; +} + /* Seconds since boot, from sysinfo() */ long jiffies(void) { diff --git a/src/util.h b/src/util.h index a65b2aad..f3b5d46f 100644 --- a/src/util.h +++ b/src/util.h @@ -64,6 +64,7 @@ char *sig2str (int sig); char *code2str (int code); void do_sleep (unsigned int sec); +void do_usleep (unsigned int usec); long jiffies (void); char *uptime (long secs, char *buf, size_t len); char *memsz (uint64_t sz, char *buf, size_t len);