AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
sys_signal.c
Go to the documentation of this file.
1
6
7#include "syscalls.h"
8
19long sys_kill(pid_t pid, int sig)
20{
21 syscall_log(LOG_DEBUG, "kill(pid=%d, sig=%d)\n", pid, sig);
22
23 /* a signal sent to ourselves is delivered on the way back to user
24 * mode, before kill() returns */
25 return signal_send(pid, sig);
26}
27
37long sys_sigaction(int sig, const struct aquila_sigaction *act, struct aquila_sigaction *oact)
38{
39 syscall_log(LOG_DEBUG, "sigaction(sig=%d, act=%p, oact=%p)\n",
40 sig, act, oact);
41
42 if (sig < 1 || sig > SIG_MAX) {
43 return -EINVAL;
44 }
45
46 struct aquila_sigaction new;
47
48 if (act && copyin(&new, act, sizeof(new))) {
49 return -EFAULT;
50 }
51
52 if (act) {
53 uintptr_t handler = new.sa_handler;
54
55 /* SIGKILL and SIGSTOP can't be caught or ignored */
56 if ((sig == SIGKILL || sig == SIGSTOP) && handler != SIG_DFL) {
57 return -EINVAL;
58 }
59
60 /* a handler must be in user memory */
61 if (handler != SIG_DFL && handler != SIG_IGN && uaccess_check((void *) handler, 1)) {
62 return -EFAULT;
63 }
64 }
65
66 if (oact && copyout(oact, &curproc->sigaction[sig], sizeof(struct aquila_sigaction))) {
67 return -EFAULT;
68 }
69
70 if (act) {
71 curproc->sigaction[sig] = new;
73 }
74
75 return 0;
76}
77
85long sys_gettimeofday(struct timeval *tv, struct timezone *tz)
86{
87 syscall_log(LOG_DEBUG, "gettimeofday(tv=%p, tz=%p)\n", tv, tz);
88
89 struct timeval ktv;
90 struct timezone ktz;
91 int err = gettimeofday(&ktv, &ktz);
92
93 if (!err && ((tv && copyout(tv, &ktv, sizeof(ktv))) || (tz && copyout(tz, &ktz, sizeof(ktz)))))
94 err = -EFAULT;
95
96 return err;
97}
98
108long sys_sigmask(int how, const sigset_t *set, sigset_t *oldset)
109{
110 syscall_log(LOG_DEBUG, "sigmask(how=%d, set=%p, oldset=%p)\n", how, set, oldset);
111
112 sigset_t kset, mask = curproc->sigmask;
113
114 if (set && copyin(&kset, set, sizeof(kset))) {
115 return -EFAULT;
116 }
117
118 if (set) {
119 switch (how) {
120 case SIG_BLOCK: mask |= kset; break;
121 case SIG_UNBLOCK: mask &= ~kset; break;
122 case SIG_SETMASK: mask = kset; break;
123 default:
124 return -EINVAL;
125 }
126 }
127
128 if (oldset && copyout(oldset, &curproc->sigmask, sizeof(sigset_t))) {
129 return -EFAULT;
130 }
131
132 /* a pending signal that is no longer blocked is delivered before this
133 * returns to user mode */
134 curproc->sigmask = mask & ~SIG_UNMASKABLE;
135 return 0;
136}
137
146long sys_sigsuspend(const sigset_t *set)
147{
148 syscall_log(LOG_DEBUG, "sigsuspend(set=%p)\n", set);
149
150 sigset_t kset;
151
152 if (copyin(&kset, set, sizeof(kset))) {
153 return -EFAULT;
154 }
155
156 struct thread *thread = curthread;
157 struct waitq wait = {0};
158
159 /* the mask it replaces goes in the handler's frame (sigreturn()
160 * restores it), or comes back if the call is restarted */
161 thread->sig_oldmask = curproc->sigmask;
163 curproc->sigmask = kset & ~SIG_UNMASKABLE;
164
165 /* sleep until a signal it doesn't block comes (nothing else wakes it
166 * up) */
167 while (!waitq_sleep(&wait))
168 ;
169
170 /* EINTR once a handler ran; restarted if none did (a stop) */
171 return -ERESTARTNOHAND;
172}
173
183{
184 syscall_log(LOG_DEBUG, "sigreturn()\n");
186
187 /* the registers are the frame's now: syscall_dispatch() doesn't set
188 * a result */
189 return 0;
190}
191
201long sys_setitimer(int which, const struct aquila_itimer *new, struct aquila_itimer *old)
202{
203 syscall_log(LOG_DEBUG, "setitimer(which=%d, new=%p, old=%p)\n", which, new, old);
204
205 struct aquila_itimer knew;
206
207 if (new && copyin(&knew, new, sizeof(knew))) {
208 return -EFAULT;
209 }
210
211 /* only the real time timer: the kernel doesn't count virtual time */
212 if (which != AQUILA_ITIMER_REAL) {
213 return -EINVAL;
214 }
215
216 struct aquila_itimer prev = {0};
217
218 /* check that the old timer can be written out before setting the new
219 * one */
220 if (old && copyout(old, &prev, sizeof(prev))) {
221 return -EFAULT;
222 }
223
224 if (new)
225 sched_alarm(curproc, knew.value, knew.interval, &prev.value, &prev.interval);
226 else
227 sched_alarm_get(curproc, &prev.value, &prev.interval);
228
229 return old ? copyout(old, &prev, sizeof(prev)) : 0;
230}
231
242long sys_nanosleep(const struct aquila_timespec *req, struct aquila_timespec *rem)
243{
244 syscall_log(LOG_DEBUG, "nanosleep(req=%p, rem=%p)\n", req, rem);
245
246 struct aquila_timespec kreq;
247
248 if (copyin(&kreq, req, sizeof(kreq))) {
249 return -EFAULT;
250 }
251
252 if (kreq.tv_nsec >= 1000000000) {
253 return -EINVAL;
254 }
255
256 /* a call restarted after a stop keeps the deadline it had; otherwise
257 * the deadline is counted from now */
258 uint64_t until = curthread->restarting ? curthread->restart_until :
259 arch_rtime_ns() + kreq.tv_sec * 1000000000ULL + kreq.tv_nsec;
260
261 curthread->restart_until = until;
262
263 if (sched_sleep(until)) {
264 /* a signal: write out the time left; the call fails with EINTR
265 * once a handler ran, or is restarted after a stop, until the same
266 * deadline */
267 if (rem) {
268 uint64_t now = arch_rtime_ns();
269 uint64_t left = now < until ? until - now : 0;
270 struct aquila_timespec krem = {
271 .tv_sec = left / 1000000000ULL,
272 .tv_nsec = left % 1000000000ULL,
273 };
274
275 if (copyout(rem, &krem, sizeof(krem))) {
276 return -EFAULT;
277 }
278 }
279
280 return -ERESTARTNOHAND;
281 }
282
283 return 0;
284}
285
293long sys_clock_gettime(int clock, struct aquila_timespec *ts)
294{
295 syscall_log(LOG_DEBUG, "clock_gettime(clock=%d, ts=%p)\n", clock, ts);
296
297 struct aquila_timespec kts;
298 struct timespec now;
299 uint64_t ns;
300
301 switch (clock) {
302 case CLOCK_REALTIME:
303 gettime(&now);
304 kts.tv_sec = now.tv_sec;
305 kts.tv_nsec = now.tv_nsec;
306 break;
307 case CLOCK_MONOTONIC:
308 ns = arch_rtime_ns();
309 kts.tv_sec = ns / 1000000000ULL;
310 kts.tv_nsec = ns % 1000000000ULL;
311 break;
312 default:
313 return -EINVAL;
314 }
315
316 return copyout(ts, &kts, sizeof(kts));
317}
void arch_sigreturn(void)
Returns from a signal handler, for sigreturn(): restores the registers, the signal mask and the FPU s...
Definition signal.c:247
static uint32_t clock
Definition arp.c:37
#define LOG_DEBUG
Definition printk.h:19
#define curproc
Definition sched.h:13
void sched_alarm_get(struct proc *proc, uint64_t *value, uint64_t *interval)
Reads what is left of a process's real time timer.
Definition sched.c:121
void sched_alarm(struct proc *proc, uint64_t value, uint64_t interval, uint64_t *old_value, uint64_t *old_interval)
Sets a process's real time timer, which setitimer() and alarm() use: the process gets SIGALRM once va...
Definition sched.c:144
int sched_sleep(uint64_t until)
Puts the current thread to sleep until a time comes, for nanosleep().
Definition sched.c:212
#define curthread
Definition sched.h:12
#define SIG_MAX
Definition signal.h:16
#define SIG_DFL
Definition signal.h:26
int signal_send(int pid, int sig)
Sends a signal as kill() does.
Definition signal.c:340
#define ERESTARTNOHAND
Definition signal.h:82
#define SIG_UNMASKABLE
Definition signal.h:85
#define SIG_IGN
Definition signal.h:27
void signal_action_set(struct proc *proc, int sig)
Discards a pending signal that sigaction() just made ignored.
Definition signal.c:201
__SIZE_TYPE__ uintptr_t
Definition stddef.h:12
unsigned long long int uint64_t
Definition stddef.h:23
An installed handler, on its interrupt's list.
Definition irq.c:19
A thread.
Definition thread.h:23
sigset_t sig_oldmask
Definition thread.h:64
int sig_oldmask_set
in sigsuspend() or pselect(): the signal mask they replaced, which the handler's frame keeps (sigretu...
Definition thread.h:63
uint32_t tv_nsec
Definition types.h:32
time_t tv_sec
Definition types.h:31
Definition waitq.h:19
long sys_sigreturn(void)
Implements sigreturn(): a signal handler returns, and the registers and signal mask that its frame sa...
Definition sys_signal.c:182
long sys_clock_gettime(int clock, struct aquila_timespec *ts)
Implements clock_gettime(): reads a clock.
Definition sys_signal.c:293
long sys_setitimer(int which, const struct aquila_itimer *new, struct aquila_itimer *old)
Implements setitimer(): sets the real time timer, which sends SIGALRM, and reads the old one.
Definition sys_signal.c:201
long sys_sigaction(int sig, const struct aquila_sigaction *act, struct aquila_sigaction *oact)
Implements sigaction(): reads a signal's action, and sets a new one.
Definition sys_signal.c:37
long sys_kill(pid_t pid, int sig)
Implements kill(): sends a signal to a process or a process group.
Definition sys_signal.c:19
long sys_gettimeofday(struct timeval *tv, struct timezone *tz)
Implements gettimeofday(): the time of day.
Definition sys_signal.c:85
long sys_nanosleep(const struct aquila_timespec *req, struct aquila_timespec *rem)
Implements nanosleep(): sleeps for a time.
Definition sys_signal.c:242
long sys_sigmask(int how, const sigset_t *set, sigset_t *oldset)
Implements sigprocmask(): reads and changes the process's signal mask.
Definition sys_signal.c:108
long sys_sigsuspend(const sigset_t *set)
Implements sigsuspend(): replaces the signal mask and waits for a signal.
Definition sys_signal.c:146
int gettime(struct timespec *ts)
Reads the wall clock (CLOCK_REALTIME).
Definition time.c:29
int gettimeofday(struct timeval *tv, struct timezone *tz)
Reads the wall clock, in microseconds, for gettimeofday().
Definition time.c:78
uint64_t arch_rtime_ns(void)
Reads the monotonic clock, which starts at boot.
Definition timer.c:56
int pid_t
Definition types.h:8
unsigned long sigset_t
Definition types.h:27
static int uaccess_check(const void *ptr, size_t len)
Checks that [ptr, ptr + len) is in user space.
Definition uaccess.h:27
int waitq_sleep(struct waitq *waitq)
Puts the current thread to sleep on a wait queue until it is woken up.
Definition waitq.c:50