]> git.corax.cc Git - corax/commitdiff
Implement some basic handling of POSIX signals
authorMatthias Kruk <m@m10k.eu>
Wed, 6 Nov 2019 06:13:55 +0000 (15:13 +0900)
committerMatthias Kruk <m@m10k.eu>
Wed, 6 Nov 2019 06:13:55 +0000 (15:13 +0900)
kernel/core/process.c

index a909903243d7ef802d3d027b32690cd114d15b07..4e7f8c99091a1d01c409b3690a0593b785a08b3d 100644 (file)
@@ -6,6 +6,7 @@
 #include <arch.h>
 #include <debug.h>
 #include <process.h>
+#include <signal.h>
 #include "fd.h"
 #include "sched.h"
 
@@ -31,6 +32,8 @@ struct process {
        int            p_status;
 
        struct fd      p_fds[16];
+
+       sighandler_t   p_sighandler[32];
 };
 
 struct proc_list {
@@ -38,6 +41,78 @@ struct proc_list {
        process_t *proc;
 };
 
+/*
+ * Possible actions:
+ *  - TERM: Terminate process
+ *  - IGN: Ignore signal
+ *  - CORE: TERM + core dump
+ *  - STOP: Stop process
+ *  - CONT: Continue stopped process
+ */
+
+static void _sig_term(int);
+static void _sig_ign(int);
+static void _sig_core(int);
+static void _sig_stop(int);
+static void _sig_cont(int);
+
+#define TERM _sig_term
+#define IGN  _sig_ign
+#define CORE _sig_core
+#define STOP _sig_stop
+#define CONT _sig_cont
+
+/*
+ * Defaults from man 7 signal:
+ *    SIGNAL    | ACTION
+ *   -----------+--------
+ *    SIGHUP    | TERM
+ *    SIGINT    | TERM
+ *    SIGQUIT   | CORE
+ *    SIGILL    | CORE
+ *    SIGABRT   | CORE
+ *    SIGFPE    | CORE
+ *    SIGKILL   | TERM
+ *    SIGSEGV   | CORE
+ *    SIGPIPE   | TERM
+ *    SIGALRM   | TERM
+ *    SIGTERM   | TERM
+ *    SIGUSR1   | TERM
+ *    SIGUSR2   | TERM
+ *    SIGCHLD   | IGN
+ *    SIGCONT   | CONT
+ *    SIGSTOP   | STOP
+ *    SIGTSTP   | STOP
+ *    SIGTTIN   | STOP
+ *    SIGTTOU   | STOP
+ *    SIGBUS    | CORE
+ *    SIGPROF   | TERM
+ *    SIGSYS    | CORE
+ *    SIGTRAP   | CORE
+ *    SIGURG    | IGN
+ *    SIGVTALRM | TERM
+ *    SIGXCPU   | CORE
+ *    SIGXFSZ   | CORE
+ *    SIGIOT    | CORE
+ *    SIGEMT    | TERM
+ *    SIGSTKFLT | TERM
+ *    SIGIO     | TERM
+ *    SIGCLT    | IGN
+ *    SIGPWR    | TERM
+ *    SIGLOST   | TERM
+ *    SIGWINCH  | IGN
+ *    SIGUNUSED | CORE
+ */
+
+/* default signal handlers */
+const static sighandler_t _sig_dfl[] = {
+       CORE, /* 0 is not defined in the standards */
+       TERM, TERM, CORE, CORE, CORE, CORE, CORE, CORE,
+       TERM, TERM, CORE, TERM, TERM, TERM, TERM, TERM,
+        IGN, CONT, STOP, STOP, STOP, STOP,  IGN, CORE,
+       CORE, TERM, TERM,  IGN, TERM, TERM, CORE, CORE
+};
+
 static pid_t _next_pid = 100;
 static struct proc_list *_procs;
 
@@ -142,6 +217,9 @@ int process_create(process_t **dst, pid_t pid, u32_t ppl, void *entry)
                        goto cleanup;
                }
 
+               /* set the default signal handlers */
+               memcpy(proc->p_sighandler, _sig_dfl, sizeof(proc->p_sighandler));
+
                proc->p_privl = ppl;
                proc->p_pid = ppid;
 
@@ -572,3 +650,161 @@ int process_detach(process_t *proc)
 
        return(ret_val);
 }
+
+int process_kill(process_t pid, int signal)
+{
+
+}
+
+int process_signal_deliver(process_t *proc, int signal)
+{
+       int ret_val;
+
+       ret_val = -EINVAL;
+
+       if(proc && signal > 0 && signal <= SIGUNUSED) {
+               stack_frame_t *kstk;
+               u32_t *vesp3;
+               u32_t *pesp3;
+               task_t *task;
+
+               /* FIXME: Need to suspend the process in order to deliver the signal safely */
+
+               /*
+                * Elect a task to handle the signal - right now, this is simple since the
+                * implementation doesn't support more than one task per process, and we
+                * can just pick the first (and only) one.
+                */
+               task = proc->p_tasks;
+               kstk = (stack_frame_t*)task->t_sp;
+
+               /*
+                * Get usable pointers to the task's stacks. The t_sp member holds the
+                * address of the kernel-mode stack that is valid inside of the kernel, so
+                * we can use it without having to perform any translations. The usermode
+                * stack will have to be translated though.
+                */
+               vesp3 = (u32_t*)kstk->prevesp;
+               ret_val = _pg_dir_vpxlate((struct pagedir*)task->t_pgdir,
+                                                                 (u32_t)vesp3, (u32_t*)&pesp3);
+
+               if(!ret_val) {
+                       u32_t *parg0;
+                       u32_t *peip;
+
+                       /* push the signal number and the return address on the userspace stack */
+
+                       /*
+                        * pesp3, pesp3 - 1, and pesp3 - 2 may not be on the same page, which would
+                        * be an atrociously hard-to-find bug.
+                        */
+#define PAGE_BASE(__addr) ((u32_t)__addr & ~(PAGE_SIZE - 1))
+#define SAME_PAGE(__x,__y) (PAGE_BASE(__x) == PAGE_BASE(__y))
+
+                       if(SAME_PAGE(vesp3, (vesp3 - 1))) {
+                               parg0 = vesp3 - 1;
+                       } else {
+                               ret_val = _pg_dir_vpxlate((struct pagedir*)task->t_pgdir,
+                                                                                 (u32_t)(vesp3 - 1), (u32_t*)&parg0);
+
+                               if(ret_val < 0) {
+                                       goto cleanup;
+                               }
+                       }
+
+                       if(SAME_PAGE(vesp3, (vesp3 - 2))) {
+                               peip = vesp3 - 2;
+                       } else {
+                               ret_val = _pg_dir_vpxlate((struct pagedir*)task->t_pgdir,
+                                                                                 (u32_t)(vesp3 - 2), (u32_t*)&peip);
+
+                               if(ret_val < 0) {
+                                       goto cleanup;
+                               }
+                       }
+
+                       *parg0 = (u32_t)signal;
+                       *peip = (u32_t)kstk->eip;
+
+                       /*
+                        * Once the task is suspended, it will be somewhere inside the kernel. This
+                        * means we can now modify the stack that the task will use to return to
+                        * userspace once it is continued.
+                        */
+                       kstk->eip = (u32_t)proc->p_sighandler[signal];
+                       kstk->prevesp -= (sizeof(kstk->prevesp) * 2);
+               }
+
+               /* let the process continue execution */
+
+               ret_val = 0;
+       }
+
+cleanup:
+       return(ret_val);
+}
+
+static void _sig_term(int sig)
+{
+       process_t *cproc;
+
+       cproc = process_get_current();
+
+       /* FIXME: terminate the process */
+
+       return;
+}
+
+static void _sig_ign(int sig)
+{
+       /* do nothing */
+       return;
+}
+
+static void _sig_core(int sig)
+{
+       process_t *cproc;
+
+       cproc = process_get_current();
+
+       /* FIXME: terminate process and generate a core dump */
+
+       return;
+}
+
+static void _sig_stop(int sig)
+{
+       process_t *cproc;
+
+       cproc = process_get_current();
+
+       /*
+        * FIXME: Stop the process
+        *  - Change the process state
+        *  - Change the state of all of its tasks
+        *  - Stop running tasks
+        *  - Place all of its tasks on the wait queue
+        *
+        * Or better yet, make it wait on a lock in the stop handler.
+        */
+
+       return;
+}
+
+static void _sig_cont(int sig)
+{
+       process_t *cproc;
+
+       cproc = process_get_current();
+
+       /*
+        * FIXME: Continue the process
+        *  - Change its state back to a runnable state
+        *  - Change the state of all of its tasks
+        *  - Place tasks on the ready queue
+        *
+        * Or better yet, release the lock that they should have been
+        * waiting on in the stop handler.
+        */
+       return;
+}