1 #include <lunaix/process.h>
2 #include <lunaix/sched.h>
3 #include <lunaix/signal.h>
4 #include <lunaix/spike.h>
5 #include <lunaix/status.h>
6 #include <lunaix/syscall.h>
8 #include <klibc/string.h>
10 extern struct scheduler sched_ctx; /* kernel/sched.c */
16 default_sighandler_term(int signum)
21 void* default_handlers[_SIG_NUM] = {
23 [_SIGINT] = default_sighandler_term,
24 [_SIGTERM] = default_sighandler_term,
25 [_SIGKILL] = default_sighandler_term,
26 [_SIGSEGV] = default_sighandler_term,
29 // Referenced in kernel/asm/x86/interrupt.S
33 if (!__current->sig_pending) {
39 31 - __builtin_clz(__current->sig_pending &
40 ~(__current->sig_mask | __current->sig_inprogress));
42 __SIGCLEAR(__current->sig_pending, sig_selected);
44 if (sig_selected == 0) {
49 // TODO: SIG{INT|TERM|KILL|SEGV} should have highest priority.
50 // Terminate the process right here if any of unmaskable signal is
53 if (!__current->sig_handler[sig_selected] &&
54 !default_handlers[sig_selected]) {
59 ptr_t ustack = __current->ustack_top & ~0xf;
61 if ((int)(ustack - USTACK_END) < (int)sizeof(struct proc_sig)) {
66 struct proc_sig* sig_ctx =
67 (struct proc_sig*)(ustack - sizeof(struct proc_sig));
71 问题是出在原本的sig_ctx->prev_context = __current->intr_ctx的上面
72 这个语句会被gcc在编译时,用更加高效的 rep movsl 来代替。
74 由于我们采用按需分页,所以在很多情况下,用户栈实际被分配的空间不允许我们进行完整的
75 注入,而需要走page fault handler进行动态分页。
79 假若我们的__current->intr_ctx注入了一半,然后产生page-fault中断,
80 那么这就会导致我们的__current->intr_ctx被这个page-fault中断导致的
81 上下文信息覆盖。那么当page-fault handler成功分配了一个页,返回,
82 拷贝也就得以进行。遗憾的是,只不过这次拷贝的内容和前面的拷贝是没有任何的关系
83 (因为此时的intr_ctx已经不是之前的intr_ctx了!)
84 而这就会导致我们保存在信号上下文中的进程上下文信息不完整,从而在soft_iret时
87 解决办法就是先吧intr_ctx拷贝到一个静态分配的区域里,然后再注入到用户栈。
89 static volatile struct proc_sigstate __temp_save;
90 __temp_save.proc_regs = __current->intr_ctx;
91 memcpy(__temp_save.fxstate, __current->fxstate, 512);
93 sig_ctx->prev_context = __temp_save;
95 sig_ctx->sig_num = sig_selected;
96 sig_ctx->signal_handler = __current->sig_handler[sig_selected];
98 if (!sig_ctx->signal_handler) {
99 // 如果没有用户自定义的Handler,则使用系统默认Handler。
100 sig_ctx->signal_handler = default_handlers[sig_selected];
103 __SIGSET(__current->sig_inprogress, sig_selected);
109 signal_send(pid_t pid, int signum)
111 if (signum < 0 || signum >= _SIG_NUM) {
112 __current->k_status = EINVAL;
116 struct proc_info* proc;
118 proc = get_process(pid);
123 } else if (pid < -1) {
124 proc = get_process(-pid);
127 // TODO: send to all process.
128 // But I don't want to support it yet.
129 __current->k_status = EINVAL;
134 struct proc_info *pos, *n;
135 llist_for_each(pos, n, &proc->grp_member, grp_member)
137 __SIGSET(pos->sig_pending, signum);
141 if (PROC_TERMINATED(proc->state)) {
142 __current->k_status = EINVAL;
145 __SIGSET(proc->sig_pending, signum);
149 __DEFINE_LXSYSCALL1(int, sigreturn, struct proc_sig, *sig_ctx)
151 memcpy(__current->fxstate, sig_ctx->prev_context.fxstate, 512);
152 __current->intr_ctx = sig_ctx->prev_context.proc_regs;
153 __current->flags &= ~PROC_FINPAUSE;
154 __SIGCLEAR(__current->sig_inprogress, sig_ctx->sig_num);
161 __DEFINE_LXSYSCALL3(int,
170 *oldset = __current->sig_mask;
171 if (how == _SIG_BLOCK) {
172 __current->sig_mask |= *set;
173 } else if (how == _SIG_UNBLOCK) {
174 __current->sig_mask &= ~(*set);
175 } else if (how == _SIG_SETMASK) {
176 __current->sig_mask = *set;
180 __current->sig_mask &= ~_SIGNAL_UNMASKABLE;
184 __DEFINE_LXSYSCALL2(int, signal, int, signum, sighandler_t, handler)
186 if (signum <= 0 || signum >= _SIG_NUM) {
190 if ((__SIGNAL(signum) & _SIGNAL_UNMASKABLE)) {
194 __current->sig_handler[signum] = (void*)handler;
202 __current->flags |= PROC_FINPAUSE;
204 while ((__current->flags & PROC_FINPAUSE)) {
208 __current->k_status = EINTR;
211 __DEFINE_LXSYSCALL(int, pause)
217 __DEFINE_LXSYSCALL2(int, kill, pid_t, pid, int, signum)
219 return signal_send(pid, signum);
222 __DEFINE_LXSYSCALL1(int, sigpending, sigset_t, *sigset)
224 *sigset = __current->sig_pending;
228 __DEFINE_LXSYSCALL1(int, sigsuspend, sigset_t, *mask)
230 sigset_t tmp = __current->sig_mask;
231 __current->sig_mask = (*mask) & ~_SIGNAL_UNMASKABLE;
233 __current->sig_mask = tmp;