SIGINT from tty, process groups and waitpid()

This commit is contained in:
Mark
2020-02-02 13:41:40 +02:00
parent 6adf9468a4
commit 5e23fc4f5c
8 changed files with 135 additions and 26 deletions
+4
View File
@@ -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);
+11
View File
@@ -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);
+3 -3
View File
@@ -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
+1
View File
@@ -36,3 +36,4 @@
#define SYSCALL_NR_SETGID 106
#define SYSCALL_NR_SETPGID 109
#define SYSCALL_NR_GETPGID 121
#define SYSCALL_NRX_WAITPID 247
+3
View File
@@ -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,
+3 -1
View File
@@ -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);
+8 -19
View File
@@ -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) {
+102 -3
View File
@@ -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);