AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
signal.c
Go to the documentation of this file.
1
13
14#include <core/system.h>
15#include <core/arch.h>
16
17#include <ds/queue.h>
18
19#include <sys/proc.h>
20#include <sys/signal.h>
21#include <sys/kthread.h>
22#include <sys/sched.h>
23
24#include <aquila/errno.h>
25
26/* What each signal does when it isn't caught (its default action). */
28 [SIGABRT] = SIGACT_ABORT,
29 [SIGALRM] = SIGACT_TERMINATE,
30 [SIGBUS] = SIGACT_ABORT,
31 [SIGCHLD] = SIGACT_IGNORE,
32 [SIGCONT] = SIGACT_CONTINUE,
33 [SIGEMT] = SIGACT_ABORT,
34 [SIGFPE] = SIGACT_ABORT,
35 [SIGHUP] = SIGACT_TERMINATE,
36 [SIGILL] = SIGACT_ABORT,
37 [SIGINT] = SIGACT_TERMINATE,
38 [SIGKILL] = SIGACT_TERMINATE,
39 [SIGPIPE] = SIGACT_TERMINATE,
40 [SIGQUIT] = SIGACT_ABORT,
41 [SIGSEGV] = SIGACT_ABORT,
42 [SIGSTOP] = SIGACT_STOP,
43 [SIGTERM] = SIGACT_TERMINATE,
44 [SIGTSTP] = SIGACT_STOP,
45 [SIGTTIN] = SIGACT_STOP,
46 [SIGTTOU] = SIGACT_STOP,
47 [SIGUSR1] = SIGACT_TERMINATE,
48 [SIGUSR2] = SIGACT_TERMINATE,
49 [SIGPOLL] = SIGACT_TERMINATE,
50 [SIGPROF] = SIGACT_TERMINATE,
51 [SIGSYS] = SIGACT_ABORT,
52 [SIGTRAP] = SIGACT_ABORT,
53 [SIGURG] = SIGACT_IGNORE,
54 [SIGWINCH] = SIGACT_IGNORE,
55 [SIGVTALRM] = SIGACT_TERMINATE,
56 [SIGXCPU] = SIGACT_ABORT,
57 [SIGXFSZ] = SIGACT_ABORT,
58 [SIGLOST] = SIGACT_TERMINATE,
59};
60
69int signal_stops(struct proc *proc, int sig)
70{
71 return proc->sigaction[sig].sa_handler == SIG_DFL &&
73}
74
77static void signal_notify_parent(struct proc *proc)
78{
79 struct proc *parent = proc->parent;
80
81 if (!parent)
82 return;
83
85
86 if (!(parent->sigaction[SIGCHLD].sa_flags & SA_NOCLDSTOP))
87 signal_proc_send(parent, SIGCHLD);
88}
89
98void signal_stop(int sig)
99{
100 struct proc *proc = curproc;
101
102 proc->stopped = sig;
105
106 while (proc->stopped)
108}
109
110#define STOP_SIGNALS ((1UL << SIGSTOP) | (1UL << SIGTSTP) | (1UL << SIGTTIN) | (1UL << SIGTTOU))
111
113static int is_stop_signal(int sig)
114{
115 return !!(STOP_SIGNALS & (1UL << sig));
116}
117
121static int signal_ignored(struct proc *proc, int sig)
122{
123 uintptr_t handler = proc->sigaction[sig].sa_handler;
124
125 if (handler == SIG_IGN)
126 return 1;
127
128 return handler == SIG_DFL && (sig_default_action[sig] == SIGACT_IGNORE ||
130}
131
138static int signal_to(struct proc *proc, int signal)
139{
140 if (signal < 0 || signal > SIG_MAX)
141 return -EINVAL;
142
143 /* the kernel's threads (process 0) take no signals */
144 if (proc == kproc)
145 return -EPERM;
146
147 /* signal 0 only checks that the process exists, and zombies can't be
148 * signalled */
149 if (!signal || !proc->running)
150 return 0;
151
152 /* a stop signal cancels a pending SIGCONT and the other way around;
153 * SIGCONT (whatever its action) and SIGKILL resume a stopped process */
154 if (is_stop_signal(signal)) {
155 proc->sig_pending &= ~(1UL << SIGCONT);
156 } else if (signal == SIGCONT || signal == SIGKILL) {
158
159 if (proc->stopped) {
160 proc->stopped = 0;
161
162 if (signal == SIGCONT) {
165 }
166
168 }
169 }
170
171 /* a signal that would be ignored is discarded when it's sent, blocked
172 * or not (POSIX allows it) */
173 if (signal_ignored(proc, signal))
174 return 0;
175
176 proc->sig_pending |= 1UL << signal;
177
178 /* a blocked signal waits; otherwise the threads sleeping where a
179 * signal may end the sleep wake up, to return to user mode and take it */
180 if (proc->sigmask & (1UL << signal))
181 return 0;
182
183 queue_for (node, &proc->threads) {
184 struct thread *thread = node->value;
185
186 if (thread->state == ISLEEP && thread->waitq)
188 else
189 sched_thread_kick(thread); /* one running on another CPU takes it now */
190 }
191
192 return 0;
193}
194
201void signal_action_set(struct proc *proc, int sig)
202{
203 if (signal_ignored(proc, sig))
204 proc->sig_pending &= ~(1UL << sig);
205}
206
216{
217 struct proc *proc = thread->owner;
218
219 return proc && proc != kproc && (proc->sig_pending & ~proc->sigmask);
220}
221
230void signal_force(struct proc *proc, int signal)
231{
232 if ((proc->sigmask & (1UL << signal)) || proc->sigaction[signal].sa_handler == SIG_IGN) {
233 proc->sigmask &= ~(1UL << signal);
234 proc->sigaction[signal].sa_handler = SIG_DFL;
235 }
236
237 signal_to(proc, signal);
238}
239
245void signal_exit(int sig)
246{
247 curproc->exit = PROC_EXIT(sig, sig);
249 arch_sleep();
250
251 for (;;);
252}
253
262int signal_take(void)
263{
264 struct proc *proc = curproc;
265
266 for (;;) {
268
269 if (!proc->running || !ready)
270 return 0;
271
272 /* SIGKILL first, then the lowest numbered signal */
273 int sig = (ready & (1UL << SIGKILL)) ? SIGKILL : __builtin_ctzl(ready);
274 proc->sig_pending &= ~(1UL << sig);
275
276 uintptr_t handler = proc->sigaction[sig].sa_handler;
277
278 if (handler == SIG_IGN)
279 continue;
280
281 if (handler != SIG_DFL)
282 return sig;
283
284 switch (sig_default_action[sig]) {
285 case SIGACT_ABORT:
286 case SIGACT_TERMINATE:
287 signal_exit(sig);
288 case SIGACT_STOP:
289 /* the terminal's stop signals don't stop an orphaned
290 * process group, since no one would continue it (POSIX);
291 * SIGSTOP does */
292 if (sig != SIGSTOP && pgrp_orphaned(proc->pgrp, NULL))
293 break;
294
295 signal_stop(sig);
296 break;
297 default:
298 break;
299 }
300 }
301}
302
310int signal_proc_send(struct proc *proc, int signal)
311{
312 return signal_to(proc, signal);
313}
314
322int signal_pgrp_send(struct pgroup *pg, int signal)
323{
324 queue_for (node, pg->procs)
325 signal_to(node->value, signal);
326
327 return 0;
328}
329
340int signal_send(pid_t pid, int signal)
341{
342 if (signal < 0 || signal > SIG_MAX)
343 return -EINVAL;
344
345 if (pid > 0) {
346 struct proc *proc = proc_pid_find(pid);
347
348 if (!proc)
349 return -ESRCH;
350
351 return signal_to(proc, signal);
352 }
353
354 if (pid == -1) {
355 int found = 0;
356
357 queue_for (node, procs) {
358 struct proc *proc = node->value;
359
360 if (proc->pid == 1 || proc == curproc || proc == kproc)
361 continue;
362
363 signal_to(proc, signal);
364 found = 1;
365 }
366
367 return found ? 0 : -ESRCH;
368 }
369
370 pid_t pgid = pid ? -pid : curproc->pgrp->pgid;
371 int found = 0;
372
373 queue_for (node, procs) {
374 struct proc *proc = node->value;
375
376 if (!proc->running || proc->pgrp->pgid != pgid)
377 continue;
378
379 found = 1;
380 signal_to(proc, signal);
381 }
382
383 return found ? 0 : -ESRCH;
384}
void arch_sleep(void)
Puts the current thread to sleep.
Definition sched.c:101
struct proc * kproc
Definition kthread.c:23
#define PROC_EXIT(info, code)
Definition proc.h:207
int pgrp_orphaned(struct pgroup *pgrp, struct proc *gone)
Says whether a process group is orphaned (POSIX): none of its members has a parent in another group o...
Definition proc.c:227
struct proc * proc_pid_find(pid_t pid)
Finds a process by its ID.
Definition proc.c:179
struct queue * procs
Definition proc.c:37
void proc_kill(struct proc *proc)
Ends a process: its threads end, its descriptors are closed, its memory is freed, its children go to ...
Definition proc.c:375
#define queue_for(n, q)
Definition queue.h:37
#define curproc
Definition sched.h:13
void sched_thread_kick(struct thread *thread)
Makes a thread that runs on another CPU enter the kernel now, rather than at its next tick: a signal ...
Definition sched.c:244
#define SIG_MAX
Definition signal.h:16
int signal_interrupts(struct thread *thread)
Says whether a thread has a signal to take, which ends a sleep that a signal may end.
Definition signal.c:215
#define SIGACT_STOP
Definition signal.h:22
int signal_proc_send(struct proc *proc, int signal)
Sends a signal to a process.
Definition signal.c:310
void signal_exit(int sig)
Ends the current process because of a signal.
Definition signal.c:245
#define SIGACT_IGNORE
Definition signal.h:21
#define SIG_DFL
Definition signal.h:26
int signal_stops(struct proc *proc, int sig)
Says whether delivering a signal to a process would stop it: the signal isn't caught,...
Definition signal.c:69
#define SIGACT_TERMINATE
Definition signal.h:20
#define WAIT_STOPPED
Definition signal.h:67
void signal_stop(int sig)
Stops the current process, until SIGCONT or SIGKILL.
Definition signal.c:98
#define WAIT_CONTINUED
Definition signal.h:68
int signal_send(int pid, int sig)
Sends a signal as kill() does.
Definition signal.c:340
#define SIGACT_CONTINUE
Definition signal.h:23
void signal_force(struct proc *proc, int signal)
Sends a signal that can't be blocked or ignored, such as the SIGSEGV of a fault: if the process block...
Definition signal.c:230
int signal_take(void)
Takes the current process's pending signals, on the way back to user mode: ignored ones are dropped,...
Definition signal.c:262
int sig_default_action[SIG_MAX+1]
Definition signal.c:27
#define SIGACT_ABORT
Definition signal.h:19
#define SIG_IGN
Definition signal.h:27
int signal_pgrp_send(struct pgroup *pg, int signal)
Sends a signal to every process of a process group.
Definition signal.c:322
void signal_action_set(struct proc *proc, int sig)
Discards a pending signal that sigaction() just made ignored.
Definition signal.c:201
#define NULL
Definition stddef.h:27
__SIZE_TYPE__ uintptr_t
Definition stddef.h:12
An installed handler, on its interrupt's list.
Definition irq.c:19
A process group: the processes of a job.
Definition proc.h:56
struct queue * procs
its processes
Definition proc.h:67
pid_t pgid
the group's ID
Definition proc.h:58
A process.
Definition proc.h:75
struct waitq stop_queue
its stopped threads sleep here
Definition proc.h:104
pid_t pid
the process's ID
Definition proc.h:77
struct proc * parent
its parent
Definition proc.h:90
struct aquila_sigaction sigaction[SIG_MAX+1]
its signal actions
Definition proc.h:157
struct waitq wait_queue
a parent waiting for a child (waitpid()) sleeps here
Definition proc.h:154
int stopped
the signal that stopped it, or 0; and what waitpid() has to report (WAIT_*)
Definition proc.h:100
int running
whether it's running
Definition proc.h:163
struct queue threads
its threads
Definition proc.h:136
sigset_t sig_pending
its pending signals, a bit (1 << sig) each: a signal sent again while it's pending is delivered once ...
Definition proc.h:148
struct pgroup * pgrp
its process group, and its node on the group's list
Definition proc.h:80
int wait_event
Definition proc.h:101
sigset_t sigmask
its blocked signals, a bit (1 << sig) each
Definition proc.h:151
A thread.
Definition thread.h:23
state_t state
its state
Definition thread.h:28
struct waitq * waitq
Definition thread.h:46
struct proc * owner
its process
Definition thread.h:31
static struct list ready
Definition sched.c:25
static int signal_ignored(struct proc *proc, int sig)
Returns whether delivering sig would do nothing: the process ignores it, or its default action is to ...
Definition signal.c:121
static int signal_to(struct proc *proc, int signal)
Sends a signal to a process: makes it pending, and if the process doesn't block it,...
Definition signal.c:138
#define STOP_SIGNALS
Definition signal.c:110
static void signal_notify_parent(struct proc *proc)
Tells a process's parent that it stopped or continued: its wait() wakes up, and it gets SIGCHLD unles...
Definition signal.c:77
static int is_stop_signal(int sig)
Returns whether sig is one of the stop signals.
Definition signal.c:113
@ ISLEEP
Definition thread.h:17
int pid_t
Definition types.h:8
unsigned long sigset_t
Definition types.h:27
void thread_wakeup(struct thread *thread)
Wakes up one thread, if it is sleeping on a wait queue.
Definition waitq.c:216
void waitq_wakeup(struct waitq *waitq)
Wakes up every thread sleeping on a wait queue, and every thread polling it.
Definition waitq.c:178
void waitq_sleep_unint(struct waitq *waitq)
Puts the current thread to sleep on a wait queue until it is woken up, whatever signals come meanwhil...
Definition waitq.c:67