[_SIGINT] = default_sighandler_term,
};
+volatile isr_param __temp_save;
// Referenced in kernel/asm/x86/interrupt.S
void*
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];
signal_send(pid_t pid, int signum)
{
if (signum < 0 || signum >= _SIG_NUM) {
- __current->k_status = LXINVL;
+ __current->k_status = EINVAL;
return -1;
}
} 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;
}
send_single:
if (PROC_TERMINATED(proc->state)) {
- __current->k_status = LXINVL;
+ __current->k_status = EINVAL;
return -1;
}
__SIGSET(proc->sig_pending, signum);
return 0;
}
-__DEFINE_LXSYSCALL(int, pause)
+void
+__do_pause()
{
__current->flags |= PROC_FINPAUSE;
- __SYSCALL_INTERRUPTIBLE({
- while ((__current->flags & PROC_FINPAUSE)) {
- sched_yield();
- }
- })
+ 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