From b804bdbfd9cbd45e5e543e2dca51650e8d93e8c2 Mon Sep 17 00:00:00 2001 From: Matthias Kruk Date: Wed, 6 Nov 2019 15:13:55 +0900 Subject: [PATCH] Implement some basic handling of POSIX signals --- kernel/core/process.c | 236 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 236 insertions(+) diff --git a/kernel/core/process.c b/kernel/core/process.c index a909903..4e7f8c9 100644 --- a/kernel/core/process.c +++ b/kernel/core/process.c @@ -6,6 +6,7 @@ #include #include #include +#include #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; +} -- 2.47.3