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