X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/6d75e31596b5ac2e638c8a31c6c2185ee4053b6b..61a1daa59589212608039e2734009870818bacd3:/lunaix-os/kernel/signal.c?ds=sidebyside diff --git a/lunaix-os/kernel/signal.c b/lunaix-os/kernel/signal.c deleted file mode 100644 index 5f0c868..0000000 --- a/lunaix-os/kernel/signal.c +++ /dev/null @@ -1,222 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -extern struct scheduler sched_ctx; /* kernel/sched.c */ - -void __USER__ -default_sighandler_term(int signum) -{ - _exit(signum); -} - -void* default_handlers[_SIG_NUM] = { - // TODO: 添加默认handler - [_SIGINT] = default_sighandler_term, [_SIGTERM] = default_sighandler_term, - [_SIGKILL] = default_sighandler_term, [_SIGSEGV] = default_sighandler_term, - [_SIGINT] = default_sighandler_term, -}; - -volatile isr_param __temp_save; -// Referenced in kernel/asm/x86/interrupt.S -void* -signal_dispatch() -{ - if (!__current->sig_pending) { - // 没有待处理信号 - return 0; - } - - int sig_selected = - 31 - __builtin_clz(__current->sig_pending & - ~(__current->sig_mask | __current->sig_inprogress)); - - __SIGCLEAR(__current->sig_pending, sig_selected); - - if (sig_selected == 0) { - // SIG0 is reserved - return 0; - } - - if (!__current->sig_handler[sig_selected] && - !default_handlers[sig_selected]) { - // 如果该信号没有handler,则忽略 - return 0; - } - - uintptr_t ustack = __current->ustack_top & ~0xf; - - if ((int)(ustack - USTACK_END) < (int)sizeof(struct proc_sig)) { - // 用户栈没有空间存放信号上下文 - return 0; - } - - struct proc_sig* sig_ctx = - (struct proc_sig*)(ustack - sizeof(struct proc_sig)); - - /* - 这是一个相当恶心的坑。 - 问题是出在原本的sig_ctx->prev_context = __current->intr_ctx的上面 - 这个语句会被gcc在编译时,用更加高效的 rep movsl 来代替。 - - 由于我们采用按需分页,所以在很多情况下,用户栈实际被分配的空间不允许我们进行完整的 - 注入,而需要走page fault handler进行动态分页。 - - 竞态条件就出现在这里! - - 假若我们的__current->intr_ctx注入了一半,然后产生page-fault中断, - 那么这就会导致我们的__current->intr_ctx被这个page-fault中断导致的 - 上下文信息覆盖。那么当page-fault handler成功分配了一个页,返回, - 拷贝也就得以进行。遗憾的是,只不过这次拷贝的内容和前面的拷贝是没有任何的关系 - (因为此时的intr_ctx已经不是之前的intr_ctx了!) - 而这就会导致我们保存在信号上下文中的进程上下文信息不完整,从而在soft_iret时 - 触发#GP。 - - 解决办法就是先吧intr_ctx拷贝到一个静态分配的区域里,然后再注入到用户栈。 - */ - __temp_save = __current->intr_ctx; - sig_ctx->prev_context = __temp_save; - - sig_ctx->sig_num = sig_selected; - sig_ctx->signal_handler = __current->sig_handler[sig_selected]; - - if (!sig_ctx->signal_handler) { - // 如果没有用户自定义的Handler,则使用系统默认Handler。 - sig_ctx->signal_handler = default_handlers[sig_selected]; - } - - __SIGSET(__current->sig_inprogress, sig_selected); - - return sig_ctx; -} - -int -signal_send(pid_t pid, int signum) -{ - if (signum < 0 || signum >= _SIG_NUM) { - __current->k_status = EINVAL; - return -1; - } - - struct proc_info* proc; - if (pid > 0) { - proc = get_process(pid); - goto send_single; - } else if (!pid) { - proc = __current; - goto send_grp; - } else if (pid < -1) { - proc = get_process(-pid); - goto send_grp; - } else { - // TODO: send to all process. - // But I don't want to support it yet. - __current->k_status = EINVAL; - return -1; - } - -send_grp: - struct proc_info *pos, *n; - llist_for_each(pos, n, &proc->grp_member, grp_member) - { - __SIGSET(pos->sig_pending, signum); - } - return 0; - -send_single: - if (PROC_TERMINATED(proc->state)) { - __current->k_status = EINVAL; - return -1; - } - __SIGSET(proc->sig_pending, signum); - return 0; -} - -__DEFINE_LXSYSCALL1(int, sigreturn, struct proc_sig, *sig_ctx) -{ - __current->intr_ctx = sig_ctx->prev_context; - __current->flags &= ~PROC_FINPAUSE; - __SIGCLEAR(__current->sig_inprogress, sig_ctx->sig_num); - schedule(); -} - -__DEFINE_LXSYSCALL3(int, - sigprocmask, - int, - how, - const sigset_t, - *set, - sigset_t, - *oldset) -{ - *oldset = __current->sig_mask; - if (how == _SIG_BLOCK) { - __current->sig_mask |= *set; - } else if (how == _SIG_UNBLOCK) { - __current->sig_mask &= ~(*set); - } else if (how == _SIG_SETMASK) { - __current->sig_mask = *set; - } else { - return 0; - } - __current->sig_mask &= ~_SIGNAL_UNMASKABLE; - return 1; -} - -__DEFINE_LXSYSCALL2(int, signal, int, signum, sighandler_t, handler) -{ - if (signum <= 0 || signum >= _SIG_NUM) { - return -1; - } - - if ((__SIGNAL(signum) & _SIGNAL_UNMASKABLE)) { - return -1; - } - - __current->sig_handler[signum] = (void*)handler; - - return 0; -} - -void -__do_pause() -{ - __current->flags |= PROC_FINPAUSE; - - while ((__current->flags & PROC_FINPAUSE)) { - sched_yieldk(); - } - - __current->k_status = EINTR; -} - -__DEFINE_LXSYSCALL(int, pause) -{ - __do_pause(); - return -1; -} - -__DEFINE_LXSYSCALL2(int, kill, pid_t, pid, int, signum) -{ - return signal_send(pid, signum); -} - -__DEFINE_LXSYSCALL1(int, sigpending, sigset_t, *sigset) -{ - *sigset = __current->sig_pending; - return 0; -} - -__DEFINE_LXSYSCALL1(int, sigsuspend, sigset_t, *mask) -{ - sigset_t tmp = __current->sig_mask; - __current->sig_mask = (*mask) & ~_SIGNAL_UNMASKABLE; - __do_pause(); - __current->sig_mask = tmp; - return -1; -} \ No newline at end of file