#include <errno.h>
#include <linux/limits.h>
#include <linux/magic.h>
+#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
}
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;
// 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);
}
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;
}
# #
#############################################################################*/
+#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
// 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")
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();
}