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