#include <lunaix/status.h>
#include <lunaix/syscall.h>
#include <lunaix/syslog.h>
+#include <lunaix/mm/valloc.h>
#include <klibc/string.h>
#include <sys/mm/mempart.h>
+// FIXME issues with signal
+
LOG_MODULE("SIG")
extern struct scheduler sched_ctx; /* kernel/sched.c */
-#define UNMASKABLE (sigset(SIGKILL) | sigset(SIGTERM))
+#define UNMASKABLE (sigset(SIGKILL) | sigset(SIGTERM) | sigset(SIGILL))
#define TERMSIG (sigset(SIGSEGV) | sigset(SIGINT) | UNMASKABLE)
#define CORE (sigset(SIGSEGV))
#define within_kstack(addr) \
- (KERNEL_STACK <= (addr) && (addr) <= KERNEL_STACK_END)
+ (KSTACK_AREA <= (addr) && (addr) <= KSTACK_AREA_END)
static inline void
-signal_terminate(int errcode)
+signal_terminate(int caused_by)
{
- terminate_proc(errcode | PEXITSIG);
+ terminate_current(caused_by | PEXITSIG);
}
// Referenced in kernel/asm/x86/interrupt.S
void*
signal_dispatch()
{
- if (!__current->sigctx.sig_pending) {
+ if (kernel_process(__current)) {
+ // signal is undefined under 'kernel process'
+ return 0;
+ }
+
+ if (!pending_sigs(current_thread)) {
// 没有待处理信号
return 0;
}
- struct sighail* psig = &__current->sigctx;
- struct sigact* prev_working = psig->inprogress;
+ struct sigregister* sigreg = __current->sigreg;
+ struct sigctx* psig = ¤t_thread->sigctx;
+ struct sigact* prev_working = active_signal(current_thread);
sigset_t mask = psig->sig_mask | (prev_working ? prev_working->sa_mask : 0);
int sig_selected = 31 - clz(psig->sig_pending & ~mask);
-
sigset_clear(psig->sig_pending, sig_selected);
- struct sigact* action = &psig->signals[sig_selected];
-
- if (sig_selected == 0) {
+ if (!sig_selected) {
// SIG0 is reserved
return 0;
}
- if (!action->sa_actor) {
+ struct sigact* action = sigreg->signals[sig_selected];
+ if (!action || !action->sa_actor) {
if (sigset_test(TERMSIG, sig_selected)) {
signal_terminate(sig_selected);
schedule();
return 0;
}
- ptr_t ustack = __current->ustack_top;
-
- if ((int)(ustack - USR_STACK) < (int)sizeof(struct proc_sig)) {
+ ptr_t ustack = current_thread->ustack_top;
+ ptr_t ustack_start = current_thread->ustack->start;
+ if ((int)(ustack - ustack_start) < (int)sizeof(struct proc_sig)) {
// 用户栈没有空间存放信号上下文
return 0;
}
sigframe->sigact = action->sa_actor;
sigframe->sighand = action->sa_handler;
- sigframe->saved_ictx = __current->intr_ctx;
+ sigframe->saved_ictx = current_thread->intr_ctx;
- action->prev = prev_working;
- psig->inprogress = action;
+ sigactive_push(current_thread, sig_selected);
return sigframe;
}
+static inline void must_inline
+__set_signal(struct thread* thread, signum_t signum)
+{
+ raise_signal(thread, signum);
+
+ // for these mutually exclusive signal
+ if (signum == SIGCONT || signum == SIGSTOP) {
+ sigset_clear(thread->sigctx.sig_pending, signum ^ 1);
+ }
+
+ struct sigact* sig = sigact_of(thread->process, signum);
+ if (sig) {
+ sig->sender = __current->pid;
+ }
+}
+
+static inline void must_inline
+__set_signal_all_threads(struct proc_info* proc, signum_t signum)
+{
+ struct thread *pos, *n;
+ llist_for_each(pos, n, &proc->threads, proc_sibs) {
+ __set_signal(pos, signum);
+ }
+}
+
void
-proc_clear_signal(struct proc_info* proc)
+thread_setsignal(struct thread* thread, signum_t signum)
{
- memset(&proc->sigctx, 0, sizeof(proc->sigctx));
+ if (unlikely(kernel_process(thread->process))) {
+ return;
+ }
+
+ __set_signal(thread, signum);
}
void
-proc_setsignal(struct proc_info* proc, int signum)
+proc_setsignal(struct proc_info* proc, signum_t signum)
{
- sigset_add(proc->sigctx.sig_pending, signum);
- proc->sigctx.signals[signum].sender = __current->pid;
+ if (unlikely(kernel_process(proc))) {
+ return;
+ }
+
+ // FIXME handle signal delivery at process level.
+ switch (signum)
+ {
+ case SIGKILL:
+ signal_terminate(signum);
+ break;
+ case SIGCONT:
+ case SIGSTOP:
+ __set_signal_all_threads(proc, signum);
+ default:
+ break;
+ }
+
+ __set_signal(proc->th_active, signum);
}
int
-signal_send(pid_t pid, int signum)
+signal_send(pid_t pid, signum_t signum)
{
- if (signum < 0 || signum >= _SIG_NUM) {
- __current->k_status = EINVAL;
+ if (signum >= _SIG_NUM) {
+ syscall_result(EINVAL);
return -1;
}
} else {
// TODO: send to all process.
// But I don't want to support it yet.
- __current->k_status = EINVAL;
+ syscall_result(EINVAL);
return -1;
}
struct proc_info *pos, *n;
llist_for_each(pos, n, &proc->grp_member, grp_member)
{
- struct sighail* sh = &pos->sigctx;
- sigset_add(sh->sig_pending, signum);
- sh->signals[signum].sender = sender_pid;
+ proc_setsignal(pos, signum);
}
send_single:
if (proc_terminated(proc)) {
- __current->k_status = EINVAL;
+ syscall_result(EINVAL);
return -1;
}
- sigset_add(proc->sigctx.sig_pending, signum);
- proc->sigctx.signals[signum].sender = sender_pid;
+ proc_setsignal(proc, signum);
return 0;
}
-__DEFINE_LXSYSCALL1(int, sigreturn, struct proc_sig, *sig_ctx)
+void
+signal_dup_context(struct sigctx* dest_ctx)
{
- __current->intr_ctx = sig_ctx->saved_ictx;
+ struct sigctx* old_ctx = ¤t_thread->sigctx;
+ memcpy(dest_ctx, old_ctx, sizeof(struct sigctx));
+}
+
+void
+signal_dup_registers(struct sigregister* dest_reg)
+{
+ struct sigregister* oldreg = __current->sigreg;
+ for (int i = 0; i < _SIG_NUM; i++) {
+ struct sigact* oldact = oldreg->signals[i];
+ if (!oldact) {
+ continue;
+ }
+
+ struct sigact* newact = valloc(sizeof(struct sigact));
+ memcpy(newact, oldact, sizeof(struct sigact));
+
+ dest_reg->signals[i] = newact;
+ }
+}
- struct sigact* current = __current->sigctx.inprogress;
- if (current) {
- __current->sigctx.inprogress = current->prev;
- current->prev = NULL;
+void
+signal_reset_context(struct sigctx* sigctx) {
+ memset(sigctx, 0, sizeof(struct sigctx));
+}
+
+void
+signal_reset_register(struct sigregister* sigreg) {
+ for (int i = 0; i < _SIG_NUM; i++) {
+ struct sigact* act = sigreg->signals[i];
+ if (act) {
+ vfree(act);
+ sigreg->signals[i] = NULL;
+ }
+ }
+}
+
+void
+signal_free_registers(struct sigregister* sigreg) {
+ signal_reset_register(sigreg);
+ vfree(sigreg);
+}
+
+static bool
+signal_set_sigmask(struct thread* thread, int how, sigset_t* oldset, sigset_t* set)
+{
+ struct sigctx* sh = ¤t_thread->sigctx;
+ *oldset = sh->sig_mask;
+
+ if (how == _SIG_BLOCK) {
+ sigset_union(sh->sig_mask, *set);
+ } else if (how == _SIG_UNBLOCK) {
+ sigset_intersect(sh->sig_mask, ~(*set));
+ } else if (how == _SIG_SETMASK) {
+ sh->sig_mask = *set;
} else {
- __current->sigctx.inprogress = NULL;
+ return false;
}
+ sigset_intersect(sh->sig_mask, ~UNMASKABLE);
+ return true;
+}
+
+__DEFINE_LXSYSCALL1(int, sigreturn, struct proc_sig, *sig_ctx)
+{
+ struct sigctx* sigctx = ¤t_thread->sigctx;
+ struct sigact* active = active_signal(current_thread);
+
+ /* We choose signal#0 as our base case, that is sig#0 means no signal.
+ Therefore, it is an ill situation to return from such sigctx.
+ */
+ if (!active) {
+ signal_terminate(SIGSEGV);
+ schedule();
+ }
+
+ current_thread->intr_ctx = sig_ctx->saved_ictx;
if (proc_terminated(__current)) {
__current->exit_code |= PEXITSIG;
} else if (sigset_test(CORE, sig_ctx->sig_num)) {
signal_terminate(sig_ctx->sig_num);
}
- ptr_t ictx = (ptr_t)__current->intr_ctx;
+ ptr_t ictx = (ptr_t)current_thread->intr_ctx;
/*
Ensure our restored context is within kernel stack
signal_terminate(SIGSEGV);
}
+ sigactive_pop(current_thread);
+
schedule();
// never reach!
__DEFINE_LXSYSCALL3(
int, sigprocmask, int, how, const sigset_t, *set, sigset_t, *oldset)
{
- struct sighail* sh = &__current->sigctx;
- *oldset = sh->sig_mask;
+ // TODO maybe it is a good opportunity to introduce a process-wide
+ // signal mask?
+
+ if (signal_set_sigmask(current_thread, how, oldset, set)) {
+ return 0;
+ }
- if (how == _SIG_BLOCK) {
- sigset_union(sh->sig_mask, *set);
- } else if (how == _SIG_UNBLOCK) {
- sigset_intersect(sh->sig_mask, ~(*set));
- } else if (how == _SIG_SETMASK) {
- sh->sig_mask = *set;
- } else {
+ syscall_result(EINVAL);
+ return -1;
+}
+
+__DEFINE_LXSYSCALL3(
+ int, th_sigmask, int, how, const sigset_t, *set, sigset_t, *oldset)
+{
+ if (signal_set_sigmask(current_thread, how, oldset, set)) {
return 0;
}
- sigset_intersect(sh->sig_mask, ~UNMASKABLE);
- return 1;
+ return EINVAL;
}
__DEFINE_LXSYSCALL2(int, sys_sigaction, int, signum, struct sigaction*, action)
return -1;
}
- struct sigact* sa = &__current->sigctx.signals[signum];
+ struct sigctx* sigctx = ¤t_thread->sigctx;
+ if (signum == sigctx->sig_active) {
+ return -1;
+ }
+
+ struct sigact* sa = sigact_of(__current, signum);
+
+ if (!sa) {
+ sa = vzalloc(sizeof(struct sigact));
+ set_sigact(__current, signum, sa);
+ }
sa->sa_actor = (void*)action->sa_sigaction;
sa->sa_handler = (void*)action->sa_handler;
__DEFINE_LXSYSCALL(int, pause)
{
- pause_current();
- sched_yieldk();
+ pause_current_thread();
+ sched_pass();
- __current->k_status = EINTR;
+ syscall_result(EINTR);
return -1;
}
__DEFINE_LXSYSCALL1(int, sigpending, sigset_t, *sigset)
{
- *sigset = __current->sigctx.sig_pending;
+ *sigset = pending_sigs(current_thread);
return 0;
}
__DEFINE_LXSYSCALL1(int, sigsuspend, sigset_t, *mask)
{
- sigset_t tmp = __current->sigctx.sig_mask;
- __current->sigctx.sig_mask = (*mask) & ~UNMASKABLE;
+ struct sigctx* sigctx = ¤t_thread->sigctx;
+ sigset_t tmp = current_thread->sigctx.sig_mask;
+ sigctx->sig_mask = (*mask) & ~UNMASKABLE;
- pause_current();
- sched_yieldk();
+ pause_current_thread();
+ sched_pass();
- __current->sigctx.sig_mask = tmp;
+ sigctx->sig_mask = tmp;
return -1;
}
\ No newline at end of file