From f438ad9b4468f8c2f2f926bfddf3fe3aef357ed7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 2 Nov 2020 19:15:58 +0100 Subject: [PATCH] module/script: send SIGINT, SIGTERM, SIGKILL, until child has died --- modules/script.c | 61 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 5 deletions(-) diff --git a/modules/script.c b/modules/script.c index 70c889f..766ea96 100644 --- a/modules/script.c +++ b/modules/script.c @@ -9,7 +9,9 @@ #include #include +#include #include +#include #define LOG_MODULE "script" #define LOG_ENABLE_DBG 0 @@ -491,12 +493,61 @@ run(struct module *mod) int ret = run_loop(mod, pid, comm_pipe[0]); close(comm_pipe[0]); - if (waitpid(pid, NULL, WNOHANG) == 0) { - killpg(pid, SIGTERM); - /* TODO: send SIGKILL after X seconds */ - waitpid(pid, NULL, 0); - } + if (waitpid(pid, NULL, WNOHANG) == 0) { + static const struct { + int signo; + int timeout; + const char *name; + } sig_info[] = { + {SIGINT, 2, "SIGINT"}, + {SIGTERM, 5, "SIGTERM"}, + {SIGKILL, 0, "SIGKILL"}, + }; + + for (size_t i = 0; i < sizeof(sig_info) / sizeof(sig_info[0]); i++) { + struct timeval start; + gettimeofday(&start, NULL); + + const int signo = sig_info[i].signo; + const int timeout = sig_info[i].timeout; + const char *const name __attribute__((unused)) = sig_info[i].name; + + LOG_DBG("sending %s to PID=%u (timeout=%ds)", name, pid, timeout); + killpg(pid, signo); + + /* + * Child is unlikely to terminate *immediately*. Wait a + * *short* period of time before checking waitpid() the + * first time + */ + usleep(10000); + + pid_t waited_pid; + while ((waited_pid = waitpid( + pid, NULL, timeout > 0 ? WNOHANG : 0)) == 0) + { + struct timeval now; + gettimeofday(&now, NULL); + + struct timeval elapsed; + timersub(&now, &start, &elapsed); + + if (elapsed.tv_sec >= timeout) + break; + + /* Don't spinning */ + thrd_yield(); + usleep(100000); /* 100ms */ + } + + if (waited_pid == pid) { + /* Child finally dead */ + break; + } + } + } else + LOG_DBG("PID=%u already terminated", pid); return ret; }