X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/9d62069fd52fa2108b677ffadc7f6138c7641757..0e1309c02f0703c050df09b71346dab60fc6df87:/lunaix-os/kernel/signal.c?ds=sidebyside diff --git a/lunaix-os/kernel/signal.c b/lunaix-os/kernel/signal.c index dd16e24..db1d4ff 100644 --- a/lunaix-os/kernel/signal.c +++ b/lunaix-os/kernel/signal.c @@ -22,6 +22,7 @@ void* default_handlers[_SIG_NUM] = { [_SIGINT] = default_sighandler_term, }; +volatile isr_param __temp_save; // Referenced in kernel/asm/x86/interrupt.S void* signal_dispatch() @@ -58,7 +59,29 @@ signal_dispatch() struct proc_sig* sig_ctx = (struct proc_sig*)(ustack - sizeof(struct proc_sig)); - sig_ctx->prev_context = __current->intr_ctx; + /* + 这是一个相当恶心的坑。 + 问题是出在原本的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]; @@ -76,7 +99,7 @@ int signal_send(pid_t pid, int signum) { if (signum < 0 || signum >= _SIG_NUM) { - __current->k_status = LXINVL; + __current->k_status = EINVAL; return -1; } @@ -93,7 +116,7 @@ signal_send(pid_t pid, int signum) } else { // TODO: send to all process. // But I don't want to support it yet. - __current->k_status = LXINVL; + __current->k_status = EINVAL; return -1; } @@ -107,7 +130,7 @@ send_grp: send_single: if (PROC_TERMINATED(proc->state)) { - __current->k_status = LXINVL; + __current->k_status = EINVAL; return -1; } __SIGSET(proc->sig_pending, signum); @@ -160,7 +183,8 @@ __DEFINE_LXSYSCALL2(int, signal, int, signum, sighandler_t, handler) return 0; } -__DEFINE_LXSYSCALL(int, pause) +void +__do_pause() { __current->flags |= PROC_FINPAUSE; @@ -170,10 +194,30 @@ __DEFINE_LXSYSCALL(int, pause) } }) __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