From: Michael Tremer Date: Sat, 27 Mar 2021 17:34:46 +0000 (+0000) Subject: cgroup: Implement function to kill all processes left X-Git-Tag: 0.9.28~1285^2~455 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1b41d3b1fa09cb876e2049a504f0331bda46066c;p=pakfire.git cgroup: Implement function to kill all processes left Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/cgroup.c b/src/libpakfire/cgroup.c index 2dfe2cbd0..8e2c713e1 100644 --- a/src/libpakfire/cgroup.c +++ b/src/libpakfire/cgroup.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -325,7 +326,7 @@ int pakfire_cgroup_detach(Pakfire pakfire, const char* group, pid_t pid) { } static ssize_t pakfire_cgroup_procs_callback(Pakfire pakfire, const char* group, - int (*func)(Pakfire pakfire, pid_t pid)) { + int (*func)(Pakfire pakfire, pid_t pid, void* data), void* data) { FILE* f = pakfire_cgroup_fopen(pakfire, group, "cgroup.procs", "r"); if (!f) return -1; @@ -343,7 +344,18 @@ static ssize_t pakfire_cgroup_procs_callback(Pakfire pakfire, const char* group, // Increment process counter num_processes++; - DEBUG(pakfire, "Read line %s\n", line); + // Process callback + if (func) { + // Parse PID + pid_t pid = strtol(line, NULL, 10); + + // Call callback function + int r = func(pakfire, pid, data); + if (r) { + fclose(f); + return -r; + } + } } fclose(f); @@ -353,5 +365,46 @@ static ssize_t pakfire_cgroup_procs_callback(Pakfire pakfire, const char* group, } ssize_t pakfire_cgroup_num_processes(Pakfire pakfire, const char* group) { - return pakfire_cgroup_procs_callback(pakfire, group, NULL); + return pakfire_cgroup_procs_callback(pakfire, group, NULL, NULL); +} + +static int send_signal(Pakfire pakfire, pid_t pid, void* data) { + int* signum = (int*)data; + + DEBUG(pakfire, "Sending signal %d to PID %d\n", *signum, pid); + + int r = kill(pid, *signum); + if (r < 0 && errno != ESRCH) { + ERROR(pakfire, "Could not send signal %d to PID %d: %s\n", + *signum, pid, strerror(errno)); + return r; + } + + return 0; +} + +int pakfire_cgroup_killall(Pakfire pakfire, const char* group) { + DEBUG(pakfire, "Killing all processes in cgroup %s\n", group); + int signum = SIGTERM; + + int count = 0; + while (1) { + // Kill all processes + size_t num_procs = pakfire_cgroup_procs_callback(pakfire, group, + send_signal, &signum); + + // If no processes are left, we are done + if (!num_procs) + return 0; + + DEBUG(pakfire, " %zu process(es) left\n", num_procs); + + // Use SIGKILL after 5 attempts with SIGTERM + if (count++ > 5 && signum == SIGTERM) + signum = SIGKILL; + + usleep(100000); + } + + return 1; } diff --git a/src/libpakfire/include/pakfire/cgroup.h b/src/libpakfire/include/pakfire/cgroup.h index e9766a676..f474faad8 100644 --- a/src/libpakfire/include/pakfire/cgroup.h +++ b/src/libpakfire/include/pakfire/cgroup.h @@ -35,6 +35,8 @@ int pakfire_cgroup_detach(Pakfire pakfire, const char* group, pid_t pid); ssize_t pakfire_cgroup_num_processes(Pakfire pakfire, const char* group); +int pakfire_cgroup_killall(Pakfire pakfire, const char* group); + #endif #endif /* PAKFIRE_CGROUP_H */ diff --git a/tests/libpakfire/cgroup.c b/tests/libpakfire/cgroup.c index f6cdb7b1b..8bd32c125 100644 --- a/tests/libpakfire/cgroup.c +++ b/tests/libpakfire/cgroup.c @@ -18,6 +18,7 @@ # # #############################################################################*/ +#include #include #include @@ -43,7 +44,7 @@ static int test_attach(const struct test* t) { // Fetch the PID of the test process pid_t pid = getpid(); - printf("This process's PID: %d\n", pid); + LOG("This process's PID: %d\n", pid); ASSERT_SUCCESS( pakfire_cgroup_create(t->pakfire, "pakfire/test") @@ -76,9 +77,65 @@ static int test_attach(const struct test* t) { return EXIT_SUCCESS; } +static void handle_signal(int signum) { + pid_t pid = getpid(); + + LOG("Process %d received signal %d\n", pid, signum); +} + +static int child_process() { + LOG("Child process started with PID %d\n", getpid()); + + signal(SIGTERM, handle_signal); + + // Do nothing + while (1) { + sleep(1); + + LOG("Child process is still alive\n"); + } + + return 0; +} + +static pid_t fork_child_process() { + pid_t pid = fork(); + ASSERT(pid >= 0); + + // Jump into child function + if (pid == 0) + return child_process(); + + return pid; +} + +static int test_killall(const struct test* t) { + ASSERT_SUCCESS( + pakfire_cgroup_create(t->pakfire, "pakfire/test") + ); + + // Launch a background we can kill :) + pid_t pid = fork_child_process(); + + // Attach child to cgroup + ASSERT_SUCCESS( + pakfire_cgroup_attach(t->pakfire, "pakfire/test", pid) + ); + + // Kill everything + ASSERT_SUCCESS( + pakfire_cgroup_killall(t->pakfire, "pakfire/test") + ); + + ASSERT_SUCCESS( + pakfire_cgroup_destroy(t->pakfire, "pakfire/test") + ); +} + int main(int argc, char** argv) { testsuite_add_test(test_create_and_destroy); testsuite_add_test(test_attach); + testsuite_add_test(test_killall); return testsuite_run(); }