kernel: Add sigaction
This commit is contained in:
parent
4c2e5da1c4
commit
2906476825
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -73,3 +73,4 @@
|
||||
#define SYS_SETGROUPS 70
|
||||
#define SYS_TIMES 71
|
||||
#define SYS_SETTIMEOFDAY 72
|
||||
#define SYS_SIGACTION 73
|
||||
|
@ -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) {
|
||||
|
@ -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]);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
15
libc/signal/sigaction.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user