kernel: Add sigaction

This commit is contained in:
K. Lange 2022-08-06 18:03:39 +09:00
parent 4c2e5da1c4
commit 2906476825
12 changed files with 135 additions and 53 deletions

View File

@ -37,9 +37,12 @@ uint16_t off_y;
static int volatile draw_lock = 0; static int volatile draw_lock = 0;
gfx_context_t * ctx; gfx_context_t * ctx;
pthread_t thread;
void sigint_handler() { void sigint_handler() {
should_exit = 1; should_exit = 1;
pthread_join(thread, NULL);
exit(1);
} }
void redraw_borders() { void redraw_borders() {
@ -145,7 +148,6 @@ int main (int argc, char ** argv) {
yutani_window_advertise_icon(yctx, wina, "Plasma", "plasma"); yutani_window_advertise_icon(yctx, wina, "Plasma", "plasma");
pthread_t thread;
pthread_create(&thread, NULL, draw_thread, NULL); pthread_create(&thread, NULL, draw_thread, NULL);
signal(SIGINT, sigint_handler); signal(SIGINT, sigint_handler);

View File

@ -772,6 +772,7 @@ static void handle_syscall(pid_t pid, struct regs * r) {
case SYS_GETTIMEOFDAY: case SYS_GETTIMEOFDAY:
/* two output args */ /* two output args */
break; break;
case SYS_SIGACTION: break;
/* These have no arguments: */ /* These have no arguments: */
case SYS_YIELD: case SYS_YIELD:
case SYS_FORK: case SYS_FORK:

View File

@ -9,6 +9,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/signal_defs.h> #include <sys/signal_defs.h>
#include <sys/signal.h>
#ifdef __x86_64__ #ifdef __x86_64__
#include <kernel/arch/x86_64/pml.h> #include <kernel/arch/x86_64/pml.h>
@ -73,6 +74,12 @@ typedef struct file_descriptors {
spin_lock_t lock; spin_lock_t lock;
} fd_table_t; } fd_table_t;
struct signal_config {
uintptr_t handler;
sigset_t mask;
int flags;
};
#define PROC_FLAG_IS_TASKLET 0x01 #define PROC_FLAG_IS_TASKLET 0x01
#define PROC_FLAG_FINISHED 0x02 #define PROC_FLAG_FINISHED 0x02
#define PROC_FLAG_STARTED 0x04 #define PROC_FLAG_STARTED 0x04
@ -114,7 +121,6 @@ typedef struct process {
list_t * wait_queue; list_t * wait_queue;
list_t * shm_mappings; list_t * shm_mappings;
list_t * node_waits; list_t * node_waits;
list_t * signal_queue;
node_t sched_node; node_t sched_node;
node_t sleep_node; node_t sleep_node;
@ -125,12 +131,14 @@ typedef struct process {
int awoken_index; int awoken_index;
thread_t thread; thread_t thread;
thread_t signal_state;
image_t image; image_t image;
spin_lock_t sched_lock; spin_lock_t sched_lock;
uintptr_t signals[NUMSIGNALS+1]; struct signal_config signals[NUMSIGNALS+1];
sigset_t blocked_signals;
sigset_t pending_signals;
sigset_t active_signals;
int supplementary_group_count; int supplementary_group_count;
gid_t * supplementary_group_list; gid_t * supplementary_group_list;
@ -273,5 +281,5 @@ extern void arch_enter_user(uintptr_t entrypoint, int argc, char * argv[], char
__attribute__((noreturn)) __attribute__((noreturn))
extern void arch_enter_signal_handler(uintptr_t,int,struct regs*); extern void arch_enter_signal_handler(uintptr_t,int,struct regs*);
extern void arch_wakeup_others(void); extern void arch_wakeup_others(void);
extern void arch_return_from_signal_handler(struct regs *r); extern int arch_return_from_signal_handler(struct regs *r);

View File

@ -16,5 +16,7 @@ typedef int sig_atomic_t;
extern sighandler_t signal(int signum, sighandler_t handler); extern sighandler_t signal(int signum, sighandler_t handler);
extern int raise(int sig); extern int raise(int sig);
extern int sigaction(int signum, struct sigaction *act, struct sigaction *oldact);
extern int sigemptyset(sigset_t *);
_End_C_Header _End_C_Header

View File

@ -16,6 +16,9 @@ _Begin_C_Header
#define SA_NOCLDSTOP 1 #define SA_NOCLDSTOP 1
#define SA_SIGINFO 2 #define SA_SIGINFO 2
#define SA_NODEFER 4
#define SA_RESETHAND 8
#define SA_RESTART 16
#if 0 #if 0
#define SIG_SETMASK 0 #define SIG_SETMASK 0

View File

@ -73,3 +73,4 @@
#define SYS_SETGROUPS 70 #define SYS_SETGROUPS 70
#define SYS_TIMES 71 #define SYS_TIMES 71
#define SYS_SETTIMEOFDAY 72 #define SYS_SETTIMEOFDAY 72
#define SYS_SIGACTION 73

View File

@ -69,7 +69,7 @@ static void _kill_it(uintptr_t addr, const char * action, const char * desc, siz
stack += sizeof(type); \ stack += sizeof(type); \
} while (0) } while (0)
void arch_return_from_signal_handler(struct regs *r) { int arch_return_from_signal_handler(struct regs *r) {
uintptr_t spsr; uintptr_t spsr;
uintptr_t sp = r->user_sp; uintptr_t sp = r->user_sp;
@ -81,6 +81,10 @@ void arch_return_from_signal_handler(struct regs *r) {
} }
arch_restore_floating((process_t*)this_core->current_process); arch_restore_floating((process_t*)this_core->current_process);
POP(sp, sigset_t, this_core->current_process->blocked_signals);
long originalSignal;
POP(sp, long, originalSignal);
/* Interrupt system call status */ /* Interrupt system call status */
POP(sp, long, this_core->current_process->interrupted_system_call); POP(sp, long, this_core->current_process->interrupted_system_call);
@ -95,6 +99,7 @@ void arch_return_from_signal_handler(struct regs *r) {
POP(sp, struct regs, *r); POP(sp, struct regs, *r);
asm volatile ("msr SP_EL0, %0" :: "r"(r->user_sp)); asm volatile ("msr SP_EL0, %0" :: "r"(r->user_sp));
return originalSignal;
} }
/** /**
@ -126,6 +131,12 @@ void arch_enter_signal_handler(uintptr_t entrypoint, int signum, struct regs *r)
PUSH(sp, long, this_core->current_process->interrupted_system_call); PUSH(sp, long, this_core->current_process->interrupted_system_call);
this_core->current_process->interrupted_system_call = 0; this_core->current_process->interrupted_system_call = 0;
PUSH(sp, long, signum);
PUSH(sp, sigset_t, this_core->current_process->blocked_signals);
struct signal_config * config = (struct signal_config*)&this_core->current_process->signals[signum];
this_core->current_process->blocked_signals |= config->mask | (1 << signum);
/* Save floating point */ /* Save floating point */
arch_save_floating((process_t*)this_core->current_process); arch_save_floating((process_t*)this_core->current_process);
for (int i = 0; i < 64; ++i) { for (int i = 0; i < 64; ++i) {

View File

@ -68,7 +68,7 @@ static void _kill_it(void) {
stack += sizeof(type); \ stack += sizeof(type); \
} while (0) } while (0)
void arch_return_from_signal_handler(struct regs *r) { int arch_return_from_signal_handler(struct regs *r) {
for (int i = 0; i < 64; ++i) { for (int i = 0; i < 64; ++i) {
POP(r->rsp, uint64_t, this_core->current_process->thread.fp_regs[63-i]); POP(r->rsp, uint64_t, this_core->current_process->thread.fp_regs[63-i]);
@ -76,6 +76,10 @@ void arch_return_from_signal_handler(struct regs *r) {
arch_restore_floating((process_t*)this_core->current_process); arch_restore_floating((process_t*)this_core->current_process);
POP(r->rsp, sigset_t, this_core->current_process->blocked_signals);
long originalSignal;
POP(r->rsp, long, originalSignal);
POP(r->rsp, long, this_core->current_process->interrupted_system_call); POP(r->rsp, long, this_core->current_process->interrupted_system_call);
struct regs out; struct regs out;
@ -91,6 +95,7 @@ void arch_return_from_signal_handler(struct regs *r) {
R(rsp); R(rsp);
r->rflags = (out.rflags & 0xcd5) | (1 << 21) | (1 << 9) | ((r->rflags & (1 << 8)) ? (1 << 8) : 0); r->rflags = (out.rflags & 0xcd5) | (1 << 21) | (1 << 9) | ((r->rflags & (1 << 8)) ? (1 << 8) : 0);
return originalSignal;
} }
@ -120,6 +125,12 @@ void arch_enter_signal_handler(uintptr_t entrypoint, int signum, struct regs *r)
PUSH(ret.rsp, long, this_core->current_process->interrupted_system_call); PUSH(ret.rsp, long, this_core->current_process->interrupted_system_call);
this_core->current_process->interrupted_system_call = 0; this_core->current_process->interrupted_system_call = 0;
PUSH(ret.rsp, long, signum);
PUSH(ret.rsp, sigset_t, this_core->current_process->blocked_signals);
struct signal_config * config = (struct signal_config*)&this_core->current_process->signals[signum];
this_core->current_process->blocked_signals |= config->mask | (1 << signum);
arch_save_floating((process_t*)this_core->current_process); arch_save_floating((process_t*)this_core->current_process);
for (int i = 0; i < 64; ++i) { for (int i = 0; i < 64; ++i) {
PUSH(ret.rsp, uint64_t, this_core->current_process->thread.fp_regs[i]); PUSH(ret.rsp, uint64_t, this_core->current_process->thread.fp_regs[i]);

View File

@ -123,11 +123,10 @@ void switch_next(void) {
mmu_set_directory(this_core->current_process->thread.page_directory->directory); mmu_set_directory(this_core->current_process->thread.page_directory->directory);
arch_set_kernel_stack(this_core->current_process->image.stack); arch_set_kernel_stack(this_core->current_process->image.stack);
if ((this_core->current_process->flags & PROC_FLAG_FINISHED) || (!this_core->current_process->signal_queue)) { if (this_core->current_process->flags & PROC_FLAG_FINISHED) {
arch_fatal_prepare(); arch_fatal_prepare();
printf("Should not have this process...\n"); printf("Should not have this process...\n");
if (this_core->current_process->flags & PROC_FLAG_FINISHED) printf("It is marked finished.\n"); if (this_core->current_process->flags & PROC_FLAG_FINISHED) printf("It is marked finished.\n");
if (!this_core->current_process->signal_queue) printf("It doesn't have a signal queue.\n");
arch_dump_traceback(); arch_dump_traceback();
arch_fatal(); arch_fatal();
__builtin_unreachable(); __builtin_unreachable();
@ -356,7 +355,6 @@ process_t * spawn_kidle(int bsp) {
* Can we make sure these are never referenced and not allocate them? */ * Can we make sure these are never referenced and not allocate them? */
idle->wait_queue = list_create("process wait queue (kidle)",idle); idle->wait_queue = list_create("process wait queue (kidle)",idle);
idle->shm_mappings = list_create("process shm mappings (kidle)",idle); idle->shm_mappings = list_create("process shm mappings (kidle)",idle);
idle->signal_queue = list_create("process signal queue (kidle)",idle);
gettimeofday(&idle->start, NULL); gettimeofday(&idle->start, NULL);
idle->thread.page_directory = malloc(sizeof(page_directory_t)); idle->thread.page_directory = malloc(sizeof(page_directory_t));
idle->thread.page_directory->refcount = 1; idle->thread.page_directory->refcount = 1;
@ -406,7 +404,6 @@ process_t * spawn_init(void) {
init->flags = PROC_FLAG_STARTED | PROC_FLAG_RUNNING; init->flags = PROC_FLAG_STARTED | PROC_FLAG_RUNNING;
init->wait_queue = list_create("process wait queue (init)", init); init->wait_queue = list_create("process wait queue (init)", init);
init->shm_mappings = list_create("process shm mapping (init)", init); init->shm_mappings = list_create("process shm mapping (init)", init);
init->signal_queue = list_create("process signal queue (init)", init);
init->sched_node.prev = NULL; init->sched_node.prev = NULL;
init->sched_node.next = NULL; init->sched_node.next = NULL;
@ -495,7 +492,6 @@ process_t * spawn_process(volatile process_t * parent, int flags) {
proc->wait_queue = list_create("process wait queue",proc); proc->wait_queue = list_create("process wait queue",proc);
proc->shm_mappings = list_create("process shm mappings",proc); proc->shm_mappings = list_create("process shm mappings",proc);
proc->signal_queue = list_create("process signal queue",proc);
proc->sched_node.value = proc; proc->sched_node.value = proc;
proc->sleep_node.value = proc; proc->sleep_node.value = proc;
@ -1216,8 +1212,6 @@ void task_exit(int retval) {
/* free whatever we can */ /* free whatever we can */
list_free(this_core->current_process->wait_queue); list_free(this_core->current_process->wait_queue);
free(this_core->current_process->wait_queue); free(this_core->current_process->wait_queue);
list_free(this_core->current_process->signal_queue);
free(this_core->current_process->signal_queue);
free(this_core->current_process->wd_name); free(this_core->current_process->wd_name);
if (this_core->current_process->node_waits) { if (this_core->current_process->node_waits) {
list_free(this_core->current_process->node_waits); list_free(this_core->current_process->node_waits);
@ -1417,7 +1411,6 @@ process_t * spawn_worker_thread(void (*entrypoint)(void * argp), const char * na
proc->wait_queue = list_create("worker thread wait queue",proc); proc->wait_queue = list_create("worker thread wait queue",proc);
proc->shm_mappings = list_create("worker thread shm mappings",proc); proc->shm_mappings = list_create("worker thread shm mappings",proc);
proc->signal_queue = list_create("worker thread signal queue",proc);
proc->sched_node.value = proc; proc->sched_node.value = proc;
proc->sleep_node.value = proc; proc->sleep_node.value = proc;

View File

@ -91,11 +91,16 @@ static char sig_defaults[] = {
* *
* @param r Registers after restoration from signal return. * @param r Registers after restoration from signal return.
*/ */
static void maybe_restart_system_call(struct regs * r) { static void maybe_restart_system_call(struct regs * r, int signum) {
if (this_core->current_process->interrupted_system_call && arch_syscall_number(r) == -ERESTARTSYS) { if (this_core->current_process->interrupted_system_call && arch_syscall_number(r) == -ERESTARTSYS) {
arch_syscall_return(r, this_core->current_process->interrupted_system_call); if (sig_defaults[signum] == SIG_DISP_Cont || (this_core->current_process->signals[signum].flags & SA_RESTART)) {
this_core->current_process->interrupted_system_call = 0; arch_syscall_return(r, this_core->current_process->interrupted_system_call);
syscall_handler(r); this_core->current_process->interrupted_system_call = 0;
syscall_handler(r);
} else {
this_core->current_process->interrupted_system_call = 0;
arch_syscall_return(r, -EINTR);
}
} }
} }
@ -119,11 +124,8 @@ static void maybe_restart_system_call(struct regs * r) {
* forward to @c arch_enter_signal_handler * forward to @c arch_enter_signal_handler
* @returns 0 if another signal needs to be handled, 1 otherwise. * @returns 0 if another signal needs to be handled, 1 otherwise.
*/ */
int handle_signal(process_t * proc, signal_t * sig, struct regs *r) { int handle_signal(process_t * proc, int signum, struct regs *r) {
uintptr_t signum = sig->signum; struct signal_config config = proc->signals[signum];
free(sig);
uintptr_t handler = proc->signals[signum];
/* Are we being traced? */ /* Are we being traced? */
if (this_core->current_process->flags & PROC_FLAG_TRACE_SIGNALS) { if (this_core->current_process->flags & PROC_FLAG_TRACE_SIGNALS) {
@ -138,7 +140,7 @@ int handle_signal(process_t * proc, signal_t * sig, struct regs *r) {
goto _ignore_signal; goto _ignore_signal;
} }
if (!handler) { if (!config.handler) {
char dowhat = sig_defaults[signum]; char dowhat = sig_defaults[signum];
if (dowhat == SIG_DISP_Term || dowhat == SIG_DISP_Core) { if (dowhat == SIG_DISP_Term || dowhat == SIG_DISP_Core) {
task_exit(((128 + signum) << 8) | signum); task_exit(((128 + signum) << 8) | signum);
@ -155,7 +157,7 @@ int handle_signal(process_t * proc, signal_t * sig, struct regs *r) {
do { do {
switch_task(0); switch_task(0);
} while (!this_core->current_process->signal_queue->length); } while (!(this_core->current_process->pending_signals & ~this_core->current_process->blocked_signals));
return 0; /* Return and handle another */ return 0; /* Return and handle another */
} else if (dowhat == SIG_DISP_Cont) { } else if (dowhat == SIG_DISP_Cont) {
@ -166,19 +168,21 @@ int handle_signal(process_t * proc, signal_t * sig, struct regs *r) {
} }
/* If the handler value is 1 we treat it as IGN. */ /* If the handler value is 1 we treat it as IGN. */
if (handler == 1) goto _ignore_signal; if (config.handler == 1) goto _ignore_signal;
proc->signals[signum] = 0; if (config.flags & SA_RESETHAND) {
proc->signals[signum].handler = 0;
}
arch_enter_signal_handler(handler, signum, r); arch_enter_signal_handler(config.handler, signum, r);
return 1; /* Should not be reachable */ return 1; /* Should not be reachable */
_ignore_signal: _ignore_signal:
/* we still need to check if we need to restart something */ /* we still need to check if we need to restart something */
maybe_restart_system_call(r); maybe_restart_system_call(r, signum);
return !this_core->current_process->signal_queue->length; return !(this_core->current_process->pending_signals & ~this_core->current_process->blocked_signals);
} }
/** /**
@ -224,12 +228,19 @@ int send_signal(pid_t process, int signal, int force_root) {
return -EINVAL; return -EINVAL;
} }
if (!receiver->signals[signal] && !sig_defaults[signal]) { if (!receiver->signals[signal].handler && !sig_defaults[signal]) {
/* If there is no handler for a signal and its default disposition is IGNORE, /* If there is no handler for a signal and its default disposition is IGNORE,
* we don't even bother sending it, to avoid having to interrupt + restart system calls. */ * we don't even bother sending it, to avoid having to interrupt + restart system calls. */
return 0; return 0;
} }
if (receiver->blocked_signals & (1 << signal)) {
spin_lock(sig_lock);
receiver->pending_signals |= (1 << signal);
spin_unlock(sig_lock);
return 0;
}
if (sig_defaults[signal] == SIG_DISP_Cont) { if (sig_defaults[signal] == SIG_DISP_Cont) {
/* XXX: I'm not sure this check is necessary? And the SUSPEND flag flip probably /* XXX: I'm not sure this check is necessary? And the SUSPEND flag flip probably
* should be on the receiving end. */ * should be on the receiving end. */
@ -242,11 +253,8 @@ int send_signal(pid_t process, int signal, int force_root) {
} }
/* Append signal to list */ /* Append signal to list */
signal_t * sig = malloc(sizeof(signal_t));
sig->signum = signal;
spin_lock(sig_lock); spin_lock(sig_lock);
list_insert(receiver->signal_queue, sig); receiver->pending_signals |= (1 << signal);
spin_unlock(sig_lock); spin_unlock(sig_lock);
/* Informs any blocking events that the process has been interrupted /* Informs any blocking events that the process has been interrupted
@ -311,20 +319,20 @@ int group_send_signal(pid_t group, int signal, int force_root) {
*/ */
void process_check_signals(struct regs * r) { void process_check_signals(struct regs * r) {
spin_lock(sig_lock); spin_lock(sig_lock);
if (this_core->current_process && if (this_core->current_process && !(this_core->current_process->flags & PROC_FLAG_FINISHED)) {
!(this_core->current_process->flags & PROC_FLAG_FINISHED) && /* Set an pending signals that were previously blocked */
this_core->current_process->signal_queue && sigset_t active_signals = this_core->current_process->pending_signals & ~this_core->current_process->blocked_signals;
this_core->current_process->signal_queue->length > 0) {
while (1) {
node_t * node = list_dequeue(this_core->current_process->signal_queue);
spin_unlock(sig_lock);
signal_t * sig = node->value; int signal = 0;
free(node); while (active_signals && signal <= NUMSIGNALS) {
if (active_signals & 1) {
if (handle_signal((process_t*)this_core->current_process,sig,r)) return; this_core->current_process->pending_signals &= ~(1 << signal);
spin_unlock(sig_lock);
spin_lock(sig_lock); if (handle_signal((process_t*)this_core->current_process, signal, r)) return;
spin_lock(sig_lock);
}
active_signals >>= 1;
signal++;
} }
} }
spin_unlock(sig_lock); spin_unlock(sig_lock);
@ -342,6 +350,9 @@ void process_check_signals(struct regs * r) {
* then to @c maybe_restart_system_call to handle system call restarts. * then to @c maybe_restart_system_call to handle system call restarts.
*/ */
void return_from_signal_handler(struct regs *r) { void return_from_signal_handler(struct regs *r) {
arch_return_from_signal_handler(r); int signum = arch_return_from_signal_handler(r);
maybe_restart_system_call(r); if (this_core->current_process->pending_signals & ~this_core->current_process->blocked_signals) {
process_check_signals(r);
}
maybe_restart_system_call(r,signum);
} }

View File

@ -15,6 +15,7 @@
#include <sys/time.h> #include <sys/time.h>
#include <sys/times.h> #include <sys/times.h>
#include <sys/ptrace.h> #include <sys/ptrace.h>
#include <sys/signal.h>
#include <syscall_nums.h> #include <syscall_nums.h>
#include <kernel/printf.h> #include <kernel/printf.h>
#include <kernel/process.h> #include <kernel/process.h>
@ -947,11 +948,33 @@ long sys_signal(long signum, uintptr_t handler) {
if (signum > NUMSIGNALS) { if (signum > NUMSIGNALS) {
return -EINVAL; return -EINVAL;
} }
uintptr_t old = this_core->current_process->signals[signum]; uintptr_t old = this_core->current_process->signals[signum].handler;
this_core->current_process->signals[signum] = handler; this_core->current_process->signals[signum].handler = handler;
this_core->current_process->signals[signum].flags = SA_RESTART;
return old; return old;
} }
long sys_sigaction(int signum, struct sigaction *act, struct sigaction *oldact) {
if (act) PTRCHECK(act,sizeof(struct sigaction),0);
if (oldact) PTRCHECK(oldact,sizeof(struct sigaction),0);
if (signum > NUMSIGNALS) return -EINVAL;
if (oldact) {
oldact->sa_handler = (_sig_func_ptr)this_core->current_process->signals[signum].handler;
oldact->sa_mask = this_core->current_process->signals[signum].mask;
oldact->sa_flags = this_core->current_process->signals[signum].flags;
}
if (act) {
this_core->current_process->signals[signum].handler = (uintptr_t)act->sa_handler;
this_core->current_process->signals[signum].mask = act->sa_mask;
this_core->current_process->signals[signum].flags = act->sa_flags;
}
return 0;
}
long sys_fswait(int c, int fds[]) { long sys_fswait(int c, int fds[]) {
PTR_VALIDATE(fds); PTR_VALIDATE(fds);
if (!fds) return -EFAULT; if (!fds) return -EFAULT;
@ -1159,6 +1182,7 @@ static long (*syscalls[])() = {
[SYS_TIMES] = sys_times, [SYS_TIMES] = sys_times,
[SYS_PTRACE] = ptrace_handle, [SYS_PTRACE] = ptrace_handle,
[SYS_SETTIMEOFDAY] = sys_settimeofday, [SYS_SETTIMEOFDAY] = sys_settimeofday,
[SYS_SIGACTION] = sys_sigaction,
[SYS_SOCKET] = net_socket, [SYS_SOCKET] = net_socket,
[SYS_SETSOCKOPT] = net_setsockopt, [SYS_SETSOCKOPT] = net_setsockopt,

15
libc/signal/sigaction.c Normal file
View File

@ -0,0 +1,15 @@
#include <sys/signal.h>
#include <syscall.h>
#include <syscall_nums.h>
#include <errno.h>
DEFN_SYSCALL3(sigaction, SYS_SIGACTION, int, struct sigaction*, struct sigaction*);
int sigaction(int signum, struct sigaction *act, struct sigaction *oldact) {
__sets_errno(syscall_sigaction(signum, act, oldact));
}
int sigemptyset(sigset_t * set) {
*set = 0;
return 0;
}