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;
gfx_context_t * ctx;
pthread_t thread;
void sigint_handler() {
should_exit = 1;
pthread_join(thread, NULL);
exit(1);
}
void redraw_borders() {
@ -145,7 +148,6 @@ int main (int argc, char ** argv) {
yutani_window_advertise_icon(yctx, wina, "Plasma", "plasma");
pthread_t thread;
pthread_create(&thread, NULL, draw_thread, NULL);
signal(SIGINT, sigint_handler);

View File

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

View File

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

View File

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

View File

@ -73,3 +73,4 @@
#define SYS_SETGROUPS 70
#define SYS_TIMES 71
#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); \
} 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 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);
POP(sp, sigset_t, this_core->current_process->blocked_signals);
long originalSignal;
POP(sp, long, originalSignal);
/* Interrupt system call status */
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);
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);
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 */
arch_save_floating((process_t*)this_core->current_process);
for (int i = 0; i < 64; ++i) {

View File

@ -68,7 +68,7 @@ static void _kill_it(void) {
stack += sizeof(type); \
} 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) {
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);
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);
struct regs out;
@ -91,6 +95,7 @@ void arch_return_from_signal_handler(struct regs *r) {
R(rsp);
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);
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);
for (int i = 0; i < 64; ++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);
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();
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->signal_queue) printf("It doesn't have a signal queue.\n");
arch_dump_traceback();
arch_fatal();
__builtin_unreachable();
@ -356,7 +355,6 @@ process_t * spawn_kidle(int bsp) {
* Can we make sure these are never referenced and not allocate them? */
idle->wait_queue = list_create("process wait queue (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);
idle->thread.page_directory = malloc(sizeof(page_directory_t));
idle->thread.page_directory->refcount = 1;
@ -406,7 +404,6 @@ process_t * spawn_init(void) {
init->flags = PROC_FLAG_STARTED | PROC_FLAG_RUNNING;
init->wait_queue = list_create("process wait queue (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.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->shm_mappings = list_create("process shm mappings",proc);
proc->signal_queue = list_create("process signal queue",proc);
proc->sched_node.value = proc;
proc->sleep_node.value = proc;
@ -1216,8 +1212,6 @@ void task_exit(int retval) {
/* free whatever we can */
list_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);
if (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->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->sleep_node.value = proc;

View File

@ -91,11 +91,16 @@ static char sig_defaults[] = {
*
* @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) {
arch_syscall_return(r, this_core->current_process->interrupted_system_call);
this_core->current_process->interrupted_system_call = 0;
syscall_handler(r);
if (sig_defaults[signum] == SIG_DISP_Cont || (this_core->current_process->signals[signum].flags & SA_RESTART)) {
arch_syscall_return(r, this_core->current_process->interrupted_system_call);
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
* @returns 0 if another signal needs to be handled, 1 otherwise.
*/
int handle_signal(process_t * proc, signal_t * sig, struct regs *r) {
uintptr_t signum = sig->signum;
free(sig);
uintptr_t handler = proc->signals[signum];
int handle_signal(process_t * proc, int signum, struct regs *r) {
struct signal_config config = proc->signals[signum];
/* Are we being traced? */
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;
}
if (!handler) {
if (!config.handler) {
char dowhat = sig_defaults[signum];
if (dowhat == SIG_DISP_Term || dowhat == SIG_DISP_Core) {
task_exit(((128 + signum) << 8) | signum);
@ -155,7 +157,7 @@ int handle_signal(process_t * proc, signal_t * sig, struct regs *r) {
do {
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 */
} 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 (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 */
_ignore_signal:
/* 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;
}
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,
* we don't even bother sending it, to avoid having to interrupt + restart system calls. */
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) {
/* XXX: I'm not sure this check is necessary? And the SUSPEND flag flip probably
* 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 */
signal_t * sig = malloc(sizeof(signal_t));
sig->signum = signal;
spin_lock(sig_lock);
list_insert(receiver->signal_queue, sig);
receiver->pending_signals |= (1 << signal);
spin_unlock(sig_lock);
/* 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) {
spin_lock(sig_lock);
if (this_core->current_process &&
!(this_core->current_process->flags & PROC_FLAG_FINISHED) &&
this_core->current_process->signal_queue &&
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);
if (this_core->current_process && !(this_core->current_process->flags & PROC_FLAG_FINISHED)) {
/* Set an pending signals that were previously blocked */
sigset_t active_signals = this_core->current_process->pending_signals & ~this_core->current_process->blocked_signals;
signal_t * sig = node->value;
free(node);
if (handle_signal((process_t*)this_core->current_process,sig,r)) return;
spin_lock(sig_lock);
int signal = 0;
while (active_signals && signal <= NUMSIGNALS) {
if (active_signals & 1) {
this_core->current_process->pending_signals &= ~(1 << signal);
spin_unlock(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);
@ -342,6 +350,9 @@ void process_check_signals(struct regs * r) {
* then to @c maybe_restart_system_call to handle system call restarts.
*/
void return_from_signal_handler(struct regs *r) {
arch_return_from_signal_handler(r);
maybe_restart_system_call(r);
int signum = arch_return_from_signal_handler(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/times.h>
#include <sys/ptrace.h>
#include <sys/signal.h>
#include <syscall_nums.h>
#include <kernel/printf.h>
#include <kernel/process.h>
@ -947,11 +948,33 @@ long sys_signal(long signum, uintptr_t handler) {
if (signum > NUMSIGNALS) {
return -EINVAL;
}
uintptr_t old = this_core->current_process->signals[signum];
this_core->current_process->signals[signum] = handler;
uintptr_t old = 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;
}
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[]) {
PTR_VALIDATE(fds);
if (!fds) return -EFAULT;
@ -1159,6 +1182,7 @@ static long (*syscalls[])() = {
[SYS_TIMES] = sys_times,
[SYS_PTRACE] = ptrace_handle,
[SYS_SETTIMEOFDAY] = sys_settimeofday,
[SYS_SIGACTION] = sys_sigaction,
[SYS_SOCKET] = net_socket,
[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;
}