SIGINT from tty, process groups and waitpid()
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -36,3 +36,4 @@
|
||||
#define SYSCALL_NR_SETGID 106
|
||||
#define SYSCALL_NR_SETPGID 109
|
||||
#define SYSCALL_NR_GETPGID 121
|
||||
#define SYSCALL_NRX_WAITPID 247
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user