chore: fix almost *ALL* warnings.
[lunaix-os.git] / lunaix-os / kernel / process / signal.c
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>
7
8 #include <klibc/string.h>
9
10 extern struct scheduler sched_ctx; /* kernel/sched.c */
11
12 extern void
13 _exit(int status);
14
15 void __USER__
16 default_sighandler_term(int signum)
17 {
18     _exit(signum);
19 }
20
21 void* default_handlers[_SIG_NUM] = {
22     // TODO: 添加默认handler
23     [_SIGINT] = default_sighandler_term,
24     [_SIGTERM] = default_sighandler_term,
25     [_SIGKILL] = default_sighandler_term,
26     [_SIGSEGV] = default_sighandler_term,
27 };
28
29 // Referenced in kernel/asm/x86/interrupt.S
30 void*
31 signal_dispatch()
32 {
33     if (!__current->sig_pending) {
34         // 没有待处理信号
35         return 0;
36     }
37
38     int sig_selected =
39       31 - __builtin_clz(__current->sig_pending &
40                          ~(__current->sig_mask | __current->sig_inprogress));
41
42     __SIGCLEAR(__current->sig_pending, sig_selected);
43
44     if (sig_selected == 0) {
45         // SIG0 is reserved
46         return 0;
47     }
48
49     // TODO: SIG{INT|TERM|KILL|SEGV} should have highest priority.
50     //       Terminate the process right here if any of unmaskable signal is
51     //       set.
52
53     if (!__current->sig_handler[sig_selected] &&
54         !default_handlers[sig_selected]) {
55         // 如果该信号没有handler,则忽略
56         return 0;
57     }
58
59     ptr_t ustack = __current->ustack_top & ~0xf;
60
61     if ((int)(ustack - USTACK_END) < (int)sizeof(struct proc_sig)) {
62         // 用户栈没有空间存放信号上下文
63         return 0;
64     }
65
66     struct proc_sig* sig_ctx =
67       (struct proc_sig*)(ustack - sizeof(struct proc_sig));
68
69     /*
70         这是一个相当恶心的坑。
71         问题是出在原本的sig_ctx->prev_context = __current->intr_ctx的上面
72         这个语句会被gcc在编译时,用更加高效的 rep movsl 来代替。
73
74         由于我们采用按需分页,所以在很多情况下,用户栈实际被分配的空间不允许我们进行完整的
75         注入,而需要走page fault handler进行动态分页。
76
77         竞态条件就出现在这里!
78
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时
85         触发#GP。
86
87         解决办法就是先吧intr_ctx拷贝到一个静态分配的区域里,然后再注入到用户栈。
88     */
89     static volatile struct proc_sigstate __temp_save;
90     __temp_save.proc_regs = __current->intr_ctx;
91     memcpy(__temp_save.fxstate, __current->fxstate, 512);
92
93     sig_ctx->prev_context = __temp_save;
94
95     sig_ctx->sig_num = sig_selected;
96     sig_ctx->signal_handler = __current->sig_handler[sig_selected];
97
98     if (!sig_ctx->signal_handler) {
99         // 如果没有用户自定义的Handler,则使用系统默认Handler。
100         sig_ctx->signal_handler = default_handlers[sig_selected];
101     }
102
103     __SIGSET(__current->sig_inprogress, sig_selected);
104
105     return sig_ctx;
106 }
107
108 int
109 signal_send(pid_t pid, int signum)
110 {
111     if (signum < 0 || signum >= _SIG_NUM) {
112         __current->k_status = EINVAL;
113         return -1;
114     }
115
116     struct proc_info* proc;
117     if (pid > 0) {
118         proc = get_process(pid);
119         goto send_single;
120     } else if (!pid) {
121         proc = __current;
122         goto send_grp;
123     } else if (pid < -1) {
124         proc = get_process(-pid);
125         goto send_grp;
126     } else {
127         // TODO: send to all process.
128         //  But I don't want to support it yet.
129         __current->k_status = EINVAL;
130         return -1;
131     }
132
133 send_grp:
134     struct proc_info *pos, *n;
135     llist_for_each(pos, n, &proc->grp_member, grp_member)
136     {
137         __SIGSET(pos->sig_pending, signum);
138     }
139
140 send_single:
141     if (PROC_TERMINATED(proc->state)) {
142         __current->k_status = EINVAL;
143         return -1;
144     }
145     __SIGSET(proc->sig_pending, signum);
146     return 0;
147 }
148
149 __DEFINE_LXSYSCALL1(int, sigreturn, struct proc_sig, *sig_ctx)
150 {
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);
155     schedule();
156
157     // never reach!
158     return 0;
159 }
160
161 __DEFINE_LXSYSCALL3(int,
162                     sigprocmask,
163                     int,
164                     how,
165                     const sigset_t,
166                     *set,
167                     sigset_t,
168                     *oldset)
169 {
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;
177     } else {
178         return 0;
179     }
180     __current->sig_mask &= ~_SIGNAL_UNMASKABLE;
181     return 1;
182 }
183
184 __DEFINE_LXSYSCALL2(int, signal, int, signum, sighandler_t, handler)
185 {
186     if (signum <= 0 || signum >= _SIG_NUM) {
187         return -1;
188     }
189
190     if ((__SIGNAL(signum) & _SIGNAL_UNMASKABLE)) {
191         return -1;
192     }
193
194     __current->sig_handler[signum] = (void*)handler;
195
196     return 0;
197 }
198
199 void
200 __do_pause()
201 {
202     __current->flags |= PROC_FINPAUSE;
203
204     while ((__current->flags & PROC_FINPAUSE)) {
205         sched_yieldk();
206     }
207
208     __current->k_status = EINTR;
209 }
210
211 __DEFINE_LXSYSCALL(int, pause)
212 {
213     __do_pause();
214     return -1;
215 }
216
217 __DEFINE_LXSYSCALL2(int, kill, pid_t, pid, int, signum)
218 {
219     return signal_send(pid, signum);
220 }
221
222 __DEFINE_LXSYSCALL1(int, sigpending, sigset_t, *sigset)
223 {
224     *sigset = __current->sig_pending;
225     return 0;
226 }
227
228 __DEFINE_LXSYSCALL1(int, sigsuspend, sigset_t, *mask)
229 {
230     sigset_t tmp = __current->sig_mask;
231     __current->sig_mask = (*mask) & ~_SIGNAL_UNMASKABLE;
232     __do_pause();
233     __current->sig_mask = tmp;
234     return -1;
235 }