feat: experimental tty console with scrollback buffer.
[lunaix-os.git] / lunaix-os / kernel / signal.c
1 #include <lunaix/lunistd.h>
2 #include <lunaix/lxsignal.h>
3 #include <lunaix/process.h>
4 #include <lunaix/sched.h>
5 #include <lunaix/signal.h>
6 #include <lunaix/spike.h>
7 #include <lunaix/status.h>
8 #include <lunaix/syscall.h>
9
10 extern struct scheduler sched_ctx; /* kernel/sched.c */
11
12 void __USER__
13 default_sighandler_term(int signum)
14 {
15     _exit(signum);
16 }
17
18 void* default_handlers[_SIG_NUM] = {
19     // TODO: 添加默认handler
20     [_SIGINT] = default_sighandler_term,
21     [_SIGTERM] = default_sighandler_term,
22     [_SIGKILL] = default_sighandler_term,
23 };
24
25 // Referenced in kernel/asm/x86/interrupt.S
26 void*
27 signal_dispatch()
28 {
29     if (!__current->sig_pending) {
30         // 没有待处理信号
31         return 0;
32     }
33
34     int sig_selected =
35       31 - __builtin_clz(__current->sig_pending &
36                          ~(__current->sig_mask | __current->sig_inprogress));
37
38     __SIGCLEAR(__current->sig_pending, sig_selected);
39
40     if (sig_selected == 0) {
41         // SIG0 is reserved
42         return 0;
43     }
44
45     if (!__current->sig_handler[sig_selected] &&
46         !default_handlers[sig_selected]) {
47         // 如果该信号没有handler,则忽略
48         return 0;
49     }
50
51     uintptr_t ustack = __current->ustack_top & ~0xf;
52
53     if ((int)(ustack - USTACK_END) < (int)sizeof(struct proc_sig)) {
54         // 用户栈没有空间存放信号上下文
55         return 0;
56     }
57
58     struct proc_sig* sig_ctx =
59       (struct proc_sig*)(ustack - sizeof(struct proc_sig));
60
61     sig_ctx->prev_context = __current->intr_ctx;
62     sig_ctx->sig_num = sig_selected;
63     sig_ctx->signal_handler = __current->sig_handler[sig_selected];
64
65     if (!sig_ctx->signal_handler) {
66         // 如果没有用户自定义的Handler,则使用系统默认Handler。
67         sig_ctx->signal_handler = default_handlers[sig_selected];
68     }
69
70     __SIGSET(__current->sig_inprogress, sig_selected);
71
72     return sig_ctx;
73 }
74
75 int
76 signal_send(pid_t pid, int signum)
77 {
78     if (signum < 0 || signum >= _SIG_NUM) {
79         __current->k_status = LXINVL;
80         return -1;
81     }
82
83     struct proc_info* proc;
84     if (pid > 0) {
85         proc = get_process(pid);
86         goto send_single;
87     } else if (!pid) {
88         proc = __current;
89         goto send_grp;
90     } else if (pid < -1) {
91         proc = get_process(-pid);
92         goto send_grp;
93     } else {
94         // TODO: send to all process.
95         //  But I don't want to support it yet.
96         __current->k_status = LXINVL;
97         return -1;
98     }
99
100 send_grp:
101     struct proc_info *pos, *n;
102     llist_for_each(pos, n, &proc->grp_member, grp_member)
103     {
104         __SIGSET(pos->sig_pending, signum);
105     }
106     return 0;
107
108 send_single:
109     if (PROC_TERMINATED(proc->state)) {
110         __current->k_status = LXINVL;
111         return -1;
112     }
113     __SIGSET(proc->sig_pending, signum);
114     return 0;
115 }
116
117 __DEFINE_LXSYSCALL1(int, sigreturn, struct proc_sig, *sig_ctx)
118 {
119     __current->intr_ctx = sig_ctx->prev_context;
120     __current->flags &= ~PROC_FINPAUSE;
121     __SIGCLEAR(__current->sig_inprogress, sig_ctx->sig_num);
122     schedule();
123 }
124
125 __DEFINE_LXSYSCALL3(int,
126                     sigprocmask,
127                     int,
128                     how,
129                     const sigset_t,
130                     *set,
131                     sigset_t,
132                     *oldset)
133 {
134     *oldset = __current->sig_mask;
135     if (how == _SIG_BLOCK) {
136         __current->sig_mask |= *set;
137     } else if (how == _SIG_UNBLOCK) {
138         __current->sig_mask &= ~(*set);
139     } else if (how == _SIG_SETMASK) {
140         __current->sig_mask = *set;
141     } else {
142         return 0;
143     }
144     __current->sig_mask &= ~_SIGNAL_UNMASKABLE;
145     return 1;
146 }
147
148 __DEFINE_LXSYSCALL2(int, signal, int, signum, sighandler_t, handler)
149 {
150     if (signum <= 0 || signum >= _SIG_NUM) {
151         return -1;
152     }
153
154     if ((__SIGNAL(signum) & _SIGNAL_UNMASKABLE)) {
155         return -1;
156     }
157
158     __current->sig_handler[signum] = (void*)handler;
159
160     return 0;
161 }
162
163 __DEFINE_LXSYSCALL(int, pause)
164 {
165     __current->flags |= PROC_FINPAUSE;
166
167     __SYSCALL_INTERRUPTIBLE({
168         while ((__current->flags & PROC_FINPAUSE)) {
169             sched_yield();
170         }
171     })
172     __current->k_status = EINTR;
173     return -1;
174 }
175
176 __DEFINE_LXSYSCALL2(int, kill, pid_t, pid, int, signum)
177 {
178     return signal_send(pid, signum);
179 }