From: Matthias Kruk Date: Sun, 19 Jan 2020 09:11:43 +0000 (+0900) Subject: Deliver signals to processes by storing pending signals and accompanying X-Git-Url: https://git.corax.cc/?a=commitdiff_plain;h=1a53f9285ed9205c642dc8a1ad869fb204cb6103;p=corax Deliver signals to processes by storing pending signals and accompanying signal information in the destination process structure, from where the destination process will retrieve it before returning from an interrupt or system call. Exception delivery is not affected by this because exceptions can be delivered directly. Function implementations added: - task_signal_handle() - process_put_signal() - process_get_signal() - process_clear_signal() - process_set_sighandler() --- diff --git a/kernel/arch/interrupt.c b/kernel/arch/interrupt.c index 14b8cc1..946a136 100644 --- a/kernel/arch/interrupt.c +++ b/kernel/arch/interrupt.c @@ -80,8 +80,36 @@ void task_signal_deliver(task_t *task, stack_frame_t *stk, int signum, siginfo_t return; } +void task_signal_handle(process_t *proc, task_t *task, stack_frame_t *stk) +{ + siginfo_t *siginfo; + int signal; + int ret_val; + + ret_val = process_get_signal(proc, &signal, &siginfo); + + if(!ret_val && signal >= 0) { + /* there is a signal to be handled */ + + dbg_printf("Process %p has a pending signal\n", proc); + + task_signal_deliver(task, stk, signal, siginfo); + + dbg_printf("Signal %u delivered to %p:%p\n", signal, proc, task); + process_clear_signal(proc); + } + + return; +} + void _int_handle(stack_frame_t ctx) { + process_t *cproc; + task_t *ctask; + + cproc = process_get_current(); + ctask = task_get_current(); + switch(ctx.intn) { #if CONFIG_APIC == 1 case INT_APICERR: @@ -138,6 +166,9 @@ void _int_handle(stack_frame_t ctx) #endif /* ! FEATURE(POSIX) */ } + /* if there is a pending signal, handle it */ + task_signal_handle(cproc, ctask, &ctx); + return; } @@ -242,7 +273,11 @@ void _exc_handle(stack_frame_t ctx) void _sys_handle(stack_frame_t ctx) { int ret_val; + process_t *cproc; + task_t *ctask; + cproc = process_get_current(); + ctask = task_get_current(); ret_val = -ENOSYS; switch(ctx.intn) { @@ -273,5 +308,8 @@ void _sys_handle(stack_frame_t ctx) ctx.eax = ret_val; + /* if there is a pending signal, handle it */ + task_signal_handle(cproc, ctask, &ctx); + return; } diff --git a/kernel/core/process.c b/kernel/core/process.c index 2fea2de..9587e28 100644 --- a/kernel/core/process.c +++ b/kernel/core/process.c @@ -38,6 +38,10 @@ struct process { enum procstate p_state; int p_status; + int p_sigpending; + siginfo_t p_siginfo; + + int p_sigflags[32]; sighandler_t p_sighandler[32]; }; @@ -325,6 +329,7 @@ int process_create(process_t **dst, pid_t pid, u32_t ppl, void *entry) memcpy(proc->p_sighandler, _sig_dfl, sizeof(proc->p_sighandler)); proc->p_privl = ppl; + proc->p_sigpending = -1; if(pid == PID_ANY) { /* no specific pid requested */ @@ -746,8 +751,9 @@ int process_signal_deliver(process_t *proc, int signal) if(cproc != proc) { dbg_printf("Signal %u to different process\n", signal); + /* TODO: Put the pending signal into the process structure */ + /* FIXME: Need to suspend the process in order to deliver the signal safely */ - process_suspend(proc); /* * Elect a task to handle the signal - right now, this is simple since the @@ -766,12 +772,17 @@ int process_signal_deliver(process_t *proc, int signal) task = task_get_current(); } + dbg_printf("Delivering signal to task %p\n", task); + if(!task) { + dbg_printf("Couldn't find a task to deliver the signal to\n"); /* this should actually never happen */ ret_val = -EBADFD; goto cleanup; } + dbg_printf("Should be delivering the irq here\n"); + kstk = (stack_frame_t*)task->t_sp; /* @@ -1046,6 +1057,25 @@ void* process_get_sighandler(process_t *proc, int signal) return((void*)proc->p_sighandler[signal]); } +int process_set_sighandler(process_t *proc, int signal, struct sigaction *sa) +{ + int ret_val; + + ret_val = -EINVAL; + + if(proc && signal >= 0 && signal <= SIGMAX) { + proc->p_sigflags[signal] = sa->sa_flags; + proc->p_sighandler[signal] = sa->sa_flags & SA_SIGINFO ? + sa->sa_sigaction : sa->sa_handler; + + dbg_printf("process_set_sighandler: %p[%u] -> %p\n", proc, signal, sa->sa_handler); + + ret_val = 0; + } + + return(ret_val); +} + int _process_hwint_deliver(pid_t pid, int irq) { process_t *proc; @@ -1054,8 +1084,114 @@ int _process_hwint_deliver(pid_t pid, int irq) ret_val = -EINVAL; proc = process_lookup(pid); + dbg_printf("Delivering irq %u to %u [%p]\n", irq, pid, proc); + + if(proc) { + siginfo_t siginfo; + + /* everything but si_signo and si_trapno is 0 for now */ + memset(&siginfo, 0, sizeof(siginfo)); + siginfo.si_signo = SIGHWINT; + siginfo.si_trapno = irq; + + ret_val = process_put_signal(proc, SIGHWINT, &siginfo); + } + + return(ret_val); +} + +/* + * process_put_signal() - Deliver a signal to a process + * + * SYNOPSIS + * int process_put_signal(process_t *proc, int signal, siginfo_t *si) + * + * DESCRIPTION + * The process_put_signal() function puts information about a signal + * into the structure of a process. + * The signal will only be stored in the process structure if there + * has not already been stored information about a pending signal. + * If the slot for the pending signal is available, it will be set to + * the signal number passed in the `signal' argument. If the `si' + * argument is not NULL, the additional signal information wil be + * copied into the process structure. + * The process_put_signal() function is atomic, in the sense that it + * will lock the process for the time that it uses the process + * structure. + * + * RETURN VALUE + * 0 The signal was successfully delivered + * -EINVAL Invalid values were passed in `proc' and/or `signal' + * -EALREADY There is already a pending signal for the process + */ +int process_put_signal(process_t *proc, int signal, siginfo_t *si) +{ + int ret_val; + + ret_val = -EINVAL; + + if(proc && signal >= 0 && signal <= SIGMAX) { + ret_val = -EALREADY; + + process_lock(proc); + + /* only deliver the signal if there is no pending one */ + if(proc->p_sigpending < 0) { + proc->p_sigpending = signal; + + /* copy the additional signal information, if provided */ + if(si) { + memcpy(&(proc->p_siginfo), si, sizeof(proc->p_siginfo)); + } + + /* process needs to be woken up if it was sleeping */ + + ret_val = 0; + } + + process_unlock(proc); + } + + return(ret_val); +} + +int process_get_signal(process_t *proc, int *signal, siginfo_t **si) +{ + int ret_val; + + ret_val = -EINVAL; + + if(proc && signal && si) { + process_lock(proc); + + if(proc->p_sigpending >= 0) { + *signal = proc->p_sigpending; + *si = (proc->p_sigflags[proc->p_sigpending] & SA_SIGINFO) ? + &(proc->p_siginfo) : NULL; + } else { + *signal = -1; + *si = NULL; + } + + process_unlock(proc); + + ret_val = 0; + } + + return(ret_val); +} + +int process_clear_signal(process_t *proc) +{ + int ret_val; + + ret_val = -EINVAL; + if(proc) { - process_signal_deliver(proc, SIGHWINT); + process_lock(proc); + proc->p_sigpending = -1; + process_unlock(proc); + ret_val = 0; } diff --git a/kernel/core/signal.c b/kernel/core/signal.c index 506dba0..ac60f05 100644 --- a/kernel/core/signal.c +++ b/kernel/core/signal.c @@ -81,6 +81,8 @@ int sys_sigaction(stack_frame_t *stk) old = (struct sigaction*)stk->edx; process_memcpy_ptok(cproc, &new, (void*)stk->ecx, sizeof(new)); + /* FIXME: Save the previous sigaction information in `old' */ + switch(signum) { case SIGHWINT: /* this is the Corax way to notify processes about hardware interrupts */ @@ -140,5 +142,10 @@ int sys_sigaction(stack_frame_t *stk) break; } + if(!ret_val) { + /* everything seems fine - update the process structure */ + ret_val = process_set_sighandler(cproc, signum, &new); + } + return(ret_val); } diff --git a/kernel/include/process.h b/kernel/include/process.h index ce2a108..4d9eef9 100644 --- a/kernel/include/process.h +++ b/kernel/include/process.h @@ -19,6 +19,7 @@ #ifndef __PROCESS_H #define __PROCESS_H +#include #include #include #include @@ -47,7 +48,10 @@ struct cxmsg* process_inbox_get(pid_t); int process_wait(pid_t); int process_signal(pid_t); int process_signal_deliver(process_t*, int); - +int process_put_signal(process_t*, int, siginfo_t*); +int process_get_signal(process_t*, int*, siginfo_t**); +int process_clear_signal(process_t*); +int process_set_sighandler(process_t*, int, struct sigaction*); void* process_get_sighandler(process_t*, int); void* process_get_tasks(process_t*);