From 6735145fa72614d5bf2d77a3fe360b62d9742bb7 Mon Sep 17 00:00:00 2001
From: FKHals <5229803-FKHals@users.noreply.gitlab.com>
Date: Mon, 24 Apr 2023 09:02:47 +0200
Subject: [PATCH] Change pb_submitter input method

to read the prediction model identifier via STDIN so that it can be
piped in.
---
 include/linux/syscalls.h             |   2 +-
 kernel/sched/pb.c                    |   3 +-
 pb_utils/pb_submitter/pb_submitter.c | 132 +++++++++++++--------------
 3 files changed, 63 insertions(+), 74 deletions(-)

diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index b7adbd31d6b2..2d1cdb391718 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -208,7 +208,7 @@ extern struct trace_event_functions exit_syscall_print_funcs;
 	static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__))
 
 
-asmlinkage long sys_pb_set_plan(struct pb_plan __user *plan);
+asmlinkage long sys_pb_set_plan(pid_t reference_proc_pid);
 asmlinkage long sys_pbm_set_root_proc(void);
 asmlinkage long sys32_quotactl(unsigned int cmd, const char __user *special,
 			       qid_t id, void __user *addr);
diff --git a/kernel/sched/pb.c b/kernel/sched/pb.c
index 06059907d607..f01375d73a0b 100644
--- a/kernel/sched/pb.c
+++ b/kernel/sched/pb.c
@@ -9,8 +9,7 @@
 
 typedef struct pb_plan pb_plan_t;
 
-SYSCALL_DEFINE1(pb_set_plan, pb_plan_t __user*, plan) {
-	pb_plan_t _plan;
+SYSCALL_DEFINE1(pb_set_plan, pid_t, reference_proc_pid) {
 	struct task_struct* task;
 	struct rq* rq;
 	struct pb_rq* pb_rq;
diff --git a/pb_utils/pb_submitter/pb_submitter.c b/pb_utils/pb_submitter/pb_submitter.c
index 048560444526..296c8d011ae2 100644
--- a/pb_utils/pb_submitter/pb_submitter.c
+++ b/pb_utils/pb_submitter/pb_submitter.c
@@ -3,126 +3,116 @@
 #include <unistd.h>
 #include <stdint.h>
 #include <stdlib.h>
+#include <signal.h>
+#include <errno.h> // errno
 
 #define PB_SET_PLAN 0x1337
 
+// FIXME DRY with the same struct in sched.h
 typedef struct {
  	    pid_t pid;
         uint64_t *inst_cnt;
         size_t num_tasks;
+        pid_t ref_pid;
 } pb_plan_t;
 
 static void usage(void)
 {
-    puts("Usage: ./pb_submitter <prog_name> <plan_file>");
+    puts("Usage: echo '<ref_proc_pid>' | ./pb_submitter <prog_name> <prog_arg_0> ...");
 }
 
-static size_t count_lines(FILE *fp)
+volatile sig_atomic_t stop;
+
+static void handler(int n)
 {
-    char c;
-    size_t lines = 0;
-    while (!feof(fp)) {
-        c = fgetc(fp);
-        if (c == '\n') {
-            lines++;
-        }
-    }
+    stop = 1;
+}
 
-    rewind(fp);
+volatile sig_atomic_t stop;
 
-    return lines;
+static void handler(int n)
+{
+    stop = 1;
 }
 
 int main(int argc, char** argv)
 {
-    if (argc < 0x3) {
-        usage();
-        return -1;
-    }
-
     int ret;
-    pb_plan_t plan = { 0 };
-    FILE *fp;
-    char *line = NULL;
-    size_t len = 0;
-    ssize_t cnt;
-    int pipes[0x2];
-
-    ret = pipe(pipes);
 
-    if (ret < 0) {
-        perror("pipe");
-        return -1;
-    }
+    pid_t ref_proc;
+    errno = 0;
 
-    fp = fopen(argv[2], "r");
-    if (fp == NULL) {
+    char buf[12]; // large enough buffer for even the largest pid
+    scanf("%11s", buf); // read what we have in stdin and drop the ending null
+    if (sscanf(buf, "%u", &ref_proc) != 1) {
+        printf("Error: Invalid stdin input (pid expected): %s; Errno: \n", strerror(errno));
         usage();
         return -1;
     }
+    printf("Got: %u\n", ref_proc);
 
-    plan.num_tasks = count_lines(fp);
-
-    uint64_t* inst_cnt = calloc(plan.num_tasks, sizeof(uint64_t));
-    if (inst_cnt == NULL) {
-        perror("calloc");
+    // TODO Add the reference proc pid as argument (arc < 3)?
+    if (argc < 2) {
+        usage();
         return -1;
     }
 
-    size_t i;
-    for (i = 0; i < plan.num_tasks; i++) {
-        cnt = getline(&line, &len, fp);
-
-        if (cnt < 0) {
-            perror("getline");
-            return -1;
-        }
-
-        uint64_t cnt = strtoull(line, NULL, 10);
-
-        if (inst_cnt == 0) {
-            puts("Inst_cnt conversion failure");
-            return -1;
-        }
-
-        inst_cnt[i] = cnt;
-    }
-
-    plan.inst_cnt = inst_cnt;
-
     pid_t pid = fork();
 
     if (pid == 0x0) {
-        char *const args[] = {argv[1], NULL};
-        char *const env[] = {NULL};
-
-        write(pipes[0x1], "a", sizeof("a"));
-
-        ret = execve(argv[1], args, env);
+        // drop the first element of argv (the name of this program) so that only
+        // the name and arguments of the program to run remain
+        char ** args = &argv[1];
+
+        puts("    ######   STOP");
+        kill(getpid(), SIGTSTP);
+        puts("    ######   CONTINUE");
+
+        // replace this process with the chosen program since we want to keep using
+        // the same PID for simplicity purposes (forking a new process would have
+        // worked as well but this process is not needed anymore anyways)
+        ret = execvp(argv[1], args);
         if (ret < 0) {
             perror("execve");
             return -1;
         }
-    }
-    else {
+    } else {
         /**
          * Wait for execve of child to finish else pb cycles are wasted inside
          * the execve function.
          *
-         * todo: find better method to do this
+         * Setup a signal handler for the SIGCHLD-Signal that the parent receives when the child is
+         * stopped (by SIGTSTP)
+         *
+         * idea for the signal handler:
+         * https://stackoverflow.com/questions/40098170/handling-sigtstp-signals-in-c/40116030#40116030
+         * idea for using it in combination with pause() instead of wait:
+         * https://stackoverflow.com/questions/12683466/after-suspending-child-process-with-sigtstp-shell-not-responding/43614414#43614414
          */
-        sleep(0x1);
-        char c;
-        read(pipes[0x0], &c, sizeof(char));
+        struct sigaction sa;
+        sa.sa_handler = handler;
+        sa.sa_flags = 0;
+        sigemptyset(&sa.sa_mask);
+        if (sigaction(SIGCHLD, &sa, NULL) == -1) {
+            perror("Couldn't set SIGCHLD handler");
+            exit(EXIT_FAILURE);
+        }
+        // wait for the child to signal the stop
+        pause();
 
-        plan.pid = pid;
+        printf("Selected plan (reference pid): %u, real pid: %u\n", ref_proc, pid);
+        ret = syscall(PB_SET_PLAN, ref_proc);
 
-        ret = syscall(PB_SET_PLAN, &plan);
+        // continue running the child
+        kill(pid, SIGCONT);
 
         if (ret < 0) {
             puts("PB_SET_PLAN failed");
             return -1;
         }
+
+        // continue running the child
+        kill(pid, SIGCONT);
     }
 
     return 0;
-- 
GitLab