Unifying External Interrupt System (#51)
[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 #include <lunaix/syslog.h>
8 #include <lunaix/mm/valloc.h>
9 #include <lunaix/switch.h>
10 #include <lunaix/kpreempt.h>
11
12 #include <klibc/string.h>
13
14 #include <asm/mempart.h>
15
16 LOG_MODULE("SIG")
17
18 extern struct scheduler sched_ctx; /* kernel/sched.c */
19
20 #define UNMASKABLE (sigset(SIGKILL) | sigset(SIGTERM) | sigset(SIGILL))
21 #define TERMSIG (sigset(SIGSEGV) | sigset(SIGINT) | UNMASKABLE)
22 #define CORE (sigset(SIGSEGV))
23 #define within_kstack(addr)                                                    \
24     (KSTACK_AREA <= (addr) && (addr) <= KSTACK_AREA_END)
25
26 static inline void
27 signal_terminate(int caused_by)
28 {
29     terminate_current(caused_by | PEXITSIG);
30 }
31
32 static inline void
33 signal_terminate_proc(struct proc_info* pcb, int caused_by)
34 {
35     terminate_proccess(pcb, caused_by | PEXITSIG);
36 }
37
38 // Referenced in kernel/asm/x86/interrupt.S
39 void
40 signal_dispatch(struct signpost_result* result)
41 {
42     continue_switch(result);
43
44     if (kernel_process(__current)) {
45         // signal is undefined under 'kernel process'
46         return;
47     }
48
49     if (!pending_sigs(current_thread)) {
50         // 没有待处理信号
51         return;
52     }
53
54     struct sigregistry* sigreg = __current->sigreg;
55     struct sigctx* psig = &current_thread->sigctx;
56     struct sigact* prev_working = active_signal(current_thread);
57     sigset_t mask = psig->sig_mask | (prev_working ? prev_working->sa_mask : 0);
58
59     int sig_selected = msbiti - clz(psig->sig_pending & ~mask);
60     sigset_clear(psig->sig_pending, sig_selected);
61
62     if (!sig_selected) {
63         // SIG0 is reserved
64         return;
65     }
66
67     struct sigact* action = sigreg->signals[sig_selected];
68     if (!action || !action->sa_actor) {
69         if (sigset_test(TERMSIG, sig_selected)) {
70             signal_terminate(sig_selected);
71             giveup_switch(result);
72         }
73         return;
74     }
75
76     ptr_t ustack = current_thread->ustack_top;
77     ptr_t ustack_start = current_thread->ustack->start;
78     if ((int)(ustack - ustack_start) < (int)sizeof(struct proc_sig)) {
79         // 用户栈没有空间存放信号上下文
80         return;
81     }
82
83     struct proc_sig* sigframe =
84         (struct proc_sig*)((ustack - sizeof(struct proc_sig)) & ~0xf);
85
86     sigframe->sig_num = sig_selected;
87     sigframe->sigact = action->sa_actor;
88     sigframe->sighand = action->sa_handler;
89
90     sigframe->saved_hstate = current_thread->hstate;
91
92     sigactive_push(current_thread, sig_selected);
93
94     redirect_switch(result, __ptr(sigframe));
95 }
96
97 static inline void must_inline
98 __set_signal(struct thread* thread, signum_t signum) 
99 {
100     raise_signal(thread, signum);
101
102     // for these mutually exclusive signal
103     if (signum == SIGCONT || signum == SIGSTOP) {
104         sigset_clear(thread->sigctx.sig_pending, signum ^ 1);
105     }
106     
107     struct sigact* sig = sigact_of(thread->process, signum);
108     if (sig) {
109         sig->sender = __current->pid;
110     }
111 }
112
113 static inline void must_inline
114 __set_signal_all_threads(struct proc_info* proc, signum_t signum) 
115 {
116     struct thread *pos, *n;
117     llist_for_each(pos, n, &proc->threads, proc_sibs) {
118         __set_signal(pos, signum);
119     }
120 }
121
122 void
123 thread_setsignal(struct thread* thread, signum_t signum)
124 {
125     if (unlikely(kernel_process(thread->process))) {
126         return;
127     }
128
129     __set_signal(thread, signum);
130 }
131
132 void
133 proc_setsignal(struct proc_info* proc, signum_t signum)
134 {
135     if (unlikely(kernel_process(proc))) {
136         return;
137     }
138
139     // FIXME handle signal delivery at process level.
140     switch (signum)
141     {
142     case SIGKILL:
143         signal_terminate_proc(proc, signum);
144         break;
145     case SIGCONT:
146     case SIGSTOP:
147         __set_signal_all_threads(proc, signum);
148     default:
149         break;
150     }
151     
152     __set_signal(proc->th_active, signum);
153 }
154
155 static inline void
156 __broadcast_group(struct proc_info* proc, signum_t signum)
157 {
158     if (proc_terminated(proc)) {
159         return;
160     }
161
162     struct proc_info *pos, *n;
163     llist_for_each(pos, n, &proc->grp_member, grp_member)
164     {
165         proc_setsignal(pos, signum);
166     }
167 }
168
169 int
170 signal_send(pid_t pid, signum_t signum)
171 {
172     if (signum >= _SIG_NUM) {
173         return EINVAL;
174     }
175
176     pid_t sender_pid = __current->pid;
177     struct proc_info* proc;
178
179     if (pid > 0) {
180         proc = get_process(pid);
181     } else if (!pid) {
182         proc = __current;
183     } else if (pid < 0) {
184         proc = get_process(-pid);
185         __broadcast_group(proc, signum);
186     } else {
187         // TODO: send to all process.
188         //  But I don't want to support it yet.
189         return EINVAL;
190     }
191
192     if (proc_terminated(proc)) {
193         return EINVAL;
194     }
195
196     proc_setsignal(proc, signum);
197
198     return 0;
199 }
200
201 void
202 signal_dup_context(struct sigctx* dest_ctx) 
203 {
204     struct sigctx* old_ctx = &current_thread->sigctx;
205     memcpy(dest_ctx, old_ctx, sizeof(struct sigctx));
206 }
207
208 void
209 signal_dup_registry(struct sigregistry* dest_reg)
210 {
211     struct sigregistry* oldreg = __current->sigreg;
212     for (int i = 0; i < _SIG_NUM; i++) {
213         struct sigact* oldact = oldreg->signals[i];
214         if (!oldact) {
215             continue;
216         }
217         
218         struct sigact* newact = valloc(sizeof(struct sigact));
219         memcpy(newact, oldact, sizeof(struct sigact));
220
221         dest_reg->signals[i] = newact;
222     }
223 }
224
225 void
226 signal_reset_context(struct sigctx* sigctx) {
227     memset(sigctx, 0, sizeof(struct sigctx));
228 }
229
230 void
231 signal_reset_registry(struct sigregistry* sigreg) {
232     for (int i = 0; i < _SIG_NUM; i++) {
233         struct sigact* act = sigreg->signals[i];
234         if (act) {
235             vfree(act);
236             sigreg->signals[i] = NULL;
237         }
238     }
239 }
240
241 void
242 signal_free_registry(struct sigregistry* sigreg) {
243     signal_reset_registry(sigreg);
244     vfree(sigreg);
245 }
246
247 static bool
248 signal_set_sigmask(struct thread* thread, int how, sigset_t* oldset, sigset_t* set)
249 {
250     struct sigctx* sh = &current_thread->sigctx;
251     *oldset = sh->sig_mask;
252
253     if (how == _SIG_BLOCK) {
254         sigset_union(sh->sig_mask, *set);
255     } else if (how == _SIG_UNBLOCK) {
256         sigset_intersect(sh->sig_mask, ~(*set));
257     } else if (how == _SIG_SETMASK) {
258         sh->sig_mask = *set;
259     } else {
260         return false;
261     }
262
263     sigset_intersect(sh->sig_mask, ~UNMASKABLE);
264     return true;
265 }
266
267 __DEFINE_LXSYSCALL1(int, sigreturn, struct proc_sig, *sig_ctx)
268 {
269     struct sigctx* sigctx = &current_thread->sigctx;
270     struct sigact* active = active_signal(current_thread);
271
272     /* We choose signal#0 as our base case, that is sig#0 means no signal.
273         Therefore, it is an ill situation to return from such sigctx.
274     */
275     if (!active) {
276         signal_terminate(SIGSEGV);
277         schedule();
278     }
279
280     current_thread->hstate = sig_ctx->saved_hstate;
281     if (proc_terminated(__current)) {
282         __current->exit_code |= PEXITSIG;
283     } else if (sigset_test(CORE, sig_ctx->sig_num)) {
284         signal_terminate(sig_ctx->sig_num);
285     }
286
287     ptr_t ictx = (ptr_t)current_thread->hstate;
288
289     /*
290         Ensure our restored context is within kernel stack
291
292         This prevent user to forge their own context such that arbitrary code
293        can be executed as supervisor level
294     */
295     if (!within_kstack(ictx)) {
296         signal_terminate(SIGSEGV);
297     }
298
299     sigactive_pop(current_thread);
300
301     schedule();
302
303     // never reach!
304     return 0;
305 }
306
307 __DEFINE_LXSYSCALL3(
308     int, sigprocmask, int, how, const sigset_t, *set, sigset_t, *oldset)
309 {
310     // TODO maybe it is a good opportunity to introduce a process-wide 
311     //      signal mask?
312     
313     if (signal_set_sigmask(current_thread, how, oldset, set)) {
314         return 0;
315     }
316
317     syscall_result(EINVAL);
318     return -1;
319 }
320
321 __DEFINE_LXSYSCALL3(
322     int, th_sigmask, int, how, const sigset_t, *set, sigset_t, *oldset)
323 {
324     if (signal_set_sigmask(current_thread, how, oldset, set)) {
325         return 0;
326     }
327
328     return EINVAL;
329 }
330
331 __DEFINE_LXSYSCALL2(int, sys_sigaction, int, signum, struct sigaction*, action)
332 {
333     if (signum <= 0 || signum >= _SIG_NUM) {
334         return -1;
335     }
336
337     if (sigset_test(UNMASKABLE, signum)) {
338         return -1;
339     }
340
341     struct sigctx* sigctx = &current_thread->sigctx;
342     if (signum == sigctx->sig_active) {
343         return -1;
344     }
345
346     struct sigact* sa = sigact_of(__current, signum);
347
348     if (!sa) {
349         sa = vzalloc(sizeof(struct sigact));
350         set_sigact(__current, signum, sa);
351     }
352
353     sa->sa_actor = (void*)action->sa_sigaction;
354     sa->sa_handler = (void*)action->sa_handler;
355     sigset_union(sa->sa_mask, sigset(signum));
356
357     return 0;
358 }
359
360 __DEFINE_LXSYSCALL(int, pause)
361 {
362     pause_current_thread();
363     yield_current();
364
365     syscall_result(EINTR);
366     return -1;
367 }
368
369 __DEFINE_LXSYSCALL2(int, kill, pid_t, pid, int, signum)
370 {
371     return syscall_result(signal_send(pid, signum));
372 }
373
374 __DEFINE_LXSYSCALL1(int, sigpending, sigset_t, *sigset)
375 {
376     *sigset = pending_sigs(current_thread);
377     return 0;
378 }
379
380 __DEFINE_LXSYSCALL1(int, sigsuspend, sigset_t, *mask)
381 {
382     struct sigctx* sigctx = &current_thread->sigctx;
383     sigset_t tmp = current_thread->sigctx.sig_mask;
384     sigctx->sig_mask = (*mask) & ~UNMASKABLE;
385
386     pause_current_thread();
387     yield_current();
388
389     sigctx->sig_mask = tmp;
390     return -1;
391 }