From 5e23fc4f5c0ecd38eb6f5cf007ed1c44f860d54c Mon Sep 17 00:00:00 2001 From: Mark Date: Sun, 2 Feb 2020 13:41:40 +0200 Subject: [PATCH] SIGINT from tty, process groups and waitpid() --- include/sys/sys_proc.h | 4 ++ include/sys/thread.h | 11 ++++ include/sys/user/signum.h | 6 +-- include/sys/user/syscall.h | 1 + sys/amd64/syscall.c | 3 ++ sys/char/tty.c | 4 +- sys/sched.c | 27 +++------- sys/thread.c | 105 +++++++++++++++++++++++++++++++++++-- 8 files changed, 135 insertions(+), 26 deletions(-) diff --git a/include/sys/sys_proc.h b/include/sys/sys_proc.h index 403d157..6008fca 100644 --- a/include/sys/sys_proc.h +++ b/include/sys/sys_proc.h @@ -12,3 +12,7 @@ uid_t sys_getuid(void); gid_t sys_getgid(void); int sys_setuid(uid_t uid); int sys_setgid(gid_t gid); + +int sys_waitpid(pid_t pid, int *status); +pid_t sys_getpgid(pid_t pid); +int sys_setpgid(pid_t pid, pid_t pgrp); diff --git a/include/sys/thread.h b/include/sys/thread.h index 2fce42b..50bb34b 100644 --- a/include/sys/thread.h +++ b/include/sys/thread.h @@ -12,9 +12,17 @@ enum thread_state { THREAD_RUNNING, THREAD_WAITING, THREAD_WAITING_IO, + THREAD_WAITING_PID, THREAD_STOPPED }; +#define thread_signal_clear(thr, signum) \ + (thr)->sigq &= ~(1ULL << ((signum) - 1)) +#define thread_signal_set(thr, signum) \ + (thr)->sigq |= 1ULL << ((signum) - 1); +#define thread_signal_pending(thr, signum) \ + ((thr)->sigq & (1ULL << ((signum) - 1))) + struct thread { // Platform data and context struct thread_data data; @@ -34,10 +42,12 @@ struct thread { // State pid_t pid; + pid_t pgid; enum thread_state state; struct thread *parent; struct thread *first_child; struct thread *next_child; + int exit_status; // Global thread list (for stuff like finding by PID) struct thread *g_prev, *g_next; @@ -54,5 +64,6 @@ struct thread *thread_find(pid_t pid); void thread_signal(struct thread *thr, int signum); int thread_check_signal(struct thread *thr, int ret); void thread_sigenter(int signum); +int thread_signal_pgid(pid_t pgid, int signum); int thread_sleep(struct thread *thr, uint64_t deadline, uint64_t *int_time); diff --git a/include/sys/user/signum.h b/include/sys/user/signum.h index d187ed3..9dc663a 100644 --- a/include/sys/user/signum.h +++ b/include/sys/user/signum.h @@ -3,9 +3,9 @@ #define SIGINT 2 #define SIGABRT 6 #define SIGKILL 9 +#define SIGUSR1 10 #define SIGSEGV 11 +#define SIGUSR2 12 #define SIGSYS 12 #define SIGTERM 15 - -#define SIGUSR1 16 -#define SIGUSR2 17 +#define SIGCHLD 17 diff --git a/include/sys/user/syscall.h b/include/sys/user/syscall.h index 85b2ca9..20e28c4 100644 --- a/include/sys/user/syscall.h +++ b/include/sys/user/syscall.h @@ -36,3 +36,4 @@ #define SYSCALL_NR_SETGID 106 #define SYSCALL_NR_SETPGID 109 #define SYSCALL_NR_GETPGID 121 +#define SYSCALL_NRX_WAITPID 247 diff --git a/sys/amd64/syscall.c b/sys/amd64/syscall.c index 02b3759..f426984 100644 --- a/sys/amd64/syscall.c +++ b/sys/amd64/syscall.c @@ -46,6 +46,9 @@ void *syscall_table[256] = { [SYSCALL_NRX_SIGENTRY] = sys_sigentry, [SYSCALL_NR_EXIT] = sys_exit, [SYSCALL_NR_SIGRETURN] = sys_sigreturn, + [SYSCALL_NRX_WAITPID] = sys_waitpid, + [SYSCALL_NR_GETPGID] = sys_getpgid, + [SYSCALL_NR_SETPGID] = sys_setpgid, // System [SYSCALL_NR_MOUNT] = sys_mount, diff --git a/sys/char/tty.c b/sys/char/tty.c index 05c9b3b..38beb86 100644 --- a/sys/char/tty.c +++ b/sys/char/tty.c @@ -2,6 +2,7 @@ #include "sys/amd64/hw/con.h" #include "sys/amd64/hw/ps2.h" #include "sys/user/termios.h" +#include "sys/user/signum.h" #include "sys/char/input.h" #include "sys/user/errno.h" #include "sys/char/line.h" @@ -10,6 +11,7 @@ #include "sys/char/tty.h" #include "sys/char/chr.h" #include "sys/string.h" +#include "sys/thread.h" #include "sys/assert.h" #include "sys/ctype.h" #include "sys/debug.h" @@ -73,7 +75,7 @@ void tty_control_write(struct chrdev *tty, char c) { break; case 'c': ring_signal(&tty->buffer, RING_SIGNAL_BRK); - //sched_signal_group(data->fg_pgid, SIGINT); + thread_signal_pgid(data->fg_pgid, SIGINT); break; default: panic("Unhandled control to TTY: ^%c\n", c); diff --git a/sys/sched.c b/sys/sched.c index 44ce9a9..69df8df 100644 --- a/sys/sched.c +++ b/sys/sched.c @@ -52,9 +52,12 @@ void sched_unqueue(struct thread *thr, enum thread_state new_state) { _assert((new_state == THREAD_WAITING) || (new_state == THREAD_STOPPED) || - (new_state == THREAD_WAITING_IO)); + (new_state == THREAD_WAITING_IO) || + (new_state == THREAD_WAITING_PID)); thr->state = new_state; + thread_check_signal(thr, 0); + if (next == thr) { thr->next = NULL; thr->prev = NULL; @@ -155,20 +158,6 @@ void sched_debug_cycle(uint64_t delta_ms) { } void yield(void) { - static uint64_t last_time = 0; - uint64_t delta = system_time - last_time; - - if (delta >= 3000000000ULL) { - if (system_time) { - struct thread *t = thread_find(1); - if (t->state != THREAD_STOPPED) { - _assert(t); - thread_signal(t, 2); - } - } - last_time = system_time; - } - struct thread *from = get_cpu()->thread; struct thread *to; @@ -180,6 +169,10 @@ void yield(void) { to = &thread_idle; } + // Check if instead of switching to a proper thread context we + // have to use signal handling + thread_check_signal(from, 0); + if (from) { from->state = THREAD_READY; } @@ -188,10 +181,6 @@ void yield(void) { get_cpu()->thread = to; context_switch_to(to, from); - - // Check if instead of switching to a proper thread context we - // have to use signal handling - thread_check_signal(from, 0); } void sched_init(void) { diff --git a/sys/thread.c b/sys/thread.c index c82b6e2..f057484 100644 --- a/sys/thread.c +++ b/sys/thread.c @@ -2,6 +2,7 @@ #include "sys/amd64/mm/phys.h" #include "sys/amd64/mm/pool.h" #include "sys/amd64/context.h" +#include "sys/user/signum.h" #include "sys/user/fcntl.h" #include "sys/binfmt_elf.h" #include "sys/user/errno.h" @@ -79,6 +80,19 @@ void thread_ioctx_fork(struct thread *dst, struct thread *src) { //// +int thread_signal_pgid(pid_t pgid, int signum) { + int ret = 0; + + for (struct thread *thr = threads_all_head; thr; thr = thr->g_next) { + if (thr->state != THREAD_STOPPED && thr->pgid == pgid) { + thread_signal(thr, signum); + ++ret; + } + } + + return ret == 0 ? -1 : ret; +} + struct thread *thread_find(pid_t pid) { for (struct thread *thr = threads_all_head; thr; thr = thr->g_next) { if (thr->pid == pid) { @@ -88,6 +102,15 @@ struct thread *thread_find(pid_t pid) { return NULL; } +struct thread *thread_child(struct thread *of, pid_t pid) { + for (struct thread *thr = of->first_child; thr; thr = thr->next_child) { + if (thr->pid == pid) { + return thr; + } + } + return NULL; +} + int thread_init(struct thread *thr, uintptr_t entry, void *arg, int user) { uintptr_t stack_pages = amd64_phys_alloc_contiguous(2); _assert(stack_pages != MM_NADDR); @@ -205,6 +228,7 @@ int thread_init(struct thread *thr, uintptr_t entry, void *arg, int user) { thr->data.rsp0 = (uintptr_t) stack; thr->sigq = 0; + thr->pgid = -1; thr->pid = -1; thread_add(thr); @@ -303,6 +327,7 @@ int sys_fork(struct sys_fork_frame *frame) { // Allocate a new PID for userspace thread dst->pid = thread_alloc_pid(1); + dst->pgid = src->pgid; dst->sigq = 0; thread_add(dst); @@ -326,6 +351,7 @@ int sys_execve(const char *path, const char **argp, const char **envp) { if (thr->space == mm_kernel) { // Have to allocate a new PID for kernel -> userspace transition thr->pid = thread_alloc_pid(1); + thr->pgid = thr->pid; // Have to remove parent/child relation for transition _assert(!thr->first_child); @@ -367,6 +393,7 @@ int sys_execve(const char *path, const char **argp, const char **envp) { void thread_sigenter(int signum) { struct thread *thr = thread_self; + kdebug("%d: Handle signal %d\n", thr->pid, signum); uintptr_t old_rsp0_top = thr->data.rsp0_top; // XXX: Either use a separate stack or ensure stuff doesn't get overwritten uintptr_t signal_rsp3 = thr->data.rsp3_base + 0x800; @@ -380,10 +407,42 @@ __attribute__((noreturn)) void sys_exit(int status) { struct thread *thr = thread_self; kdebug("Thread %d exited with status %d\n", thr->pid, status); + thr->exit_status = status; + + if (thr->parent) { + thread_signal(thr->parent, SIGCHLD); + } + sched_unqueue(thr, THREAD_STOPPED); panic("This code shouldn't run\n"); } +int sys_waitpid(pid_t pid, int *status) { + struct thread *thr = thread_self; + _assert(thr); + struct thread *chld = thread_child(thr, pid); + + if (!chld) { + return -ECHILD; + } + + while (1) { + sched_unqueue(thr, THREAD_WAITING_PID); + if (thread_signal_pending(thr, SIGCHLD)) { + thread_signal_clear(thr, SIGCHLD); + break; + } + // Handle any other pending signal + kdebug("Waken up by some other signal, continuing\n"); + thread_check_signal(thr, 0); + } + + if (status) { + *status = chld->exit_status; + } + return 0; +} + int thread_sleep(struct thread *thr, uint64_t deadline, uint64_t *int_time) { thr->sleep_deadline = deadline; timer_add_sleep(thr); @@ -401,9 +460,11 @@ void sys_sigreturn(void) { void thread_signal(struct thread *thr, int signum) { if (thr == thread_self) { + kdebug("Signal will be handled now\n"); thread_sigenter(signum); } else { - thr->sigq |= 1ULL << (signum - 1); + kdebug("Signal will be handled later\n"); + thread_signal_set(thr, signum); if (thr->state == THREAD_WAITING) { timer_remove_sleep(thr); @@ -424,7 +485,6 @@ int thread_check_signal(struct thread *thr, int ret) { break; } } - kdebug("%d: Handle signal %d\n", thr->pid, signum); _assert(signum); thread_sigenter(signum); @@ -450,7 +510,7 @@ int sys_kill(pid_t pid, int signum) { thr = NULL; } - if (!thr) { + if (!thr || thr->state == THREAD_STOPPED) { return -ESRCH; } @@ -485,6 +545,45 @@ pid_t sys_getpid(void) { return thr->pid; } +pid_t sys_getpgid(pid_t pid) { + struct thread *thr; + + if (pid == 0) { + thr = get_cpu()->thread; + _assert(thr); + } else { + thr = thread_find(pid); + } + + if (!thr) { + return -ESRCH; + } + + return thr->pgid; +} + +int sys_setpgid(pid_t pid, pid_t pgrp) { + struct thread *thr = get_cpu()->thread; + _assert(thr); + + if (pid == 0 && pgrp == 0) { + thr->pgid = thr->pid; + return 0; + } + + // Find child with pid pid (guess only children can be setpgid'd) + struct thread *chld = thread_child(thr, pid); + if (!chld) { + return -ESRCH; + } + if (chld->pgid != thr->pgid) { + return -EACCES; + } + chld->pgid = pgrp; + + return 0; +} + int sys_setuid(uid_t uid) { struct thread *thr = get_cpu()->thread; _assert(thr);