source: mainline/uspace/lib/posix/signal.c@ 4cf8ca6

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 4cf8ca6 was 4cf8ca6, checked in by Petr Koupy <petr.koupy@…>, 14 years ago

Various minor commenting (no change in functionality).

  • Property mode set to 100644
File size: 9.2 KB
Line 
1/*
2 * Copyright (c) 2011 Jiri Zarevucky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libposix
30 * @{
31 */
32/** @file Signal handling.
33 */
34
35#define LIBPOSIX_INTERNAL
36
37#include "signal.h"
38#include "internal/common.h"
39#include "limits.h"
40#include "stdlib.h"
41#include "string.h"
42#include "errno.h"
43
44#include "libc/fibril_synch.h"
45#include "libc/task.h"
46
47// TODO: documentation
48
49/* Used to serialize signal handling. */
50static FIBRIL_MUTEX_INITIALIZE(_signal_mutex);
51
52static posix_sigset_t _signal_mask = 0;
53
54#define DEFAULT_HANDLER { .sa_handler = SIG_DFL, \
55 .sa_mask = 0, .sa_flags = 0, .sa_sigaction = NULL }
56
57static struct posix_sigaction _signal_actions[_TOP_SIGNAL + 1] = {
58 DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER,
59 DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER,
60 DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER,
61 DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER,
62 DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER,
63 DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER,
64 DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER
65};
66
67/**
68 *
69 * @param signo
70 */
71void __posix_default_signal_handler(int signo)
72{
73 switch (signo) {
74 case SIGABRT:
75 abort();
76 case SIGQUIT:
77 fprintf(stderr, "Quit signal raised. Exiting.");
78 exit(EXIT_FAILURE);
79 case SIGINT:
80 fprintf(stderr, "Interrupt signal caught. Exiting.");
81 exit(EXIT_FAILURE);
82 case SIGTERM:
83 fprintf(stderr, "Termination signal caught. Exiting.");
84 exit(EXIT_FAILURE);
85 case SIGSTOP:
86 fprintf(stderr, "Stop signal caught, but unsupported. Ignoring.");
87 break;
88 case SIGKILL:
89 /* This will only occur when raise or similar is called. */
90 /* Commit suicide. */
91 task_kill(task_get_id());
92
93 /* Should not be reached. */
94 abort();
95 case SIGFPE:
96 case SIGBUS:
97 case SIGILL:
98 case SIGSEGV:
99 posix_psignal(signo, "Hardware exception raised by user code");
100 abort();
101 case SIGSYS:
102 case SIGXCPU:
103 case SIGXFSZ:
104 case SIGTRAP:
105 case SIGHUP:
106 case SIGPIPE:
107 case SIGPOLL:
108 case SIGURG:
109 case SIGTSTP:
110 case SIGTTIN:
111 case SIGTTOU:
112 posix_psignal(signo, "Unsupported signal caught");
113 abort();
114 case SIGCHLD:
115 case SIGUSR1:
116 case SIGUSR2:
117 case SIGALRM:
118 case SIGVTALRM:
119 case SIGPROF:
120 case SIGCONT:
121 /* ignored */
122 break;
123 }
124}
125
126/**
127 *
128 * @param signo
129 */
130void __posix_hold_signal_handler(int signo)
131{
132 /* Nothing */
133}
134
135/**
136 *
137 * @param signo
138 */
139void __posix_ignore_signal_handler(int signo)
140{
141 /* Nothing */
142}
143
144/**
145 *
146 * @param set
147 * @return
148 */
149int posix_sigemptyset(posix_sigset_t *set)
150{
151 assert(set != NULL);
152
153 *set = 0;
154 return 0;
155}
156
157/**
158 *
159 * @param set
160 * @return
161 */
162int posix_sigfillset(posix_sigset_t *set)
163{
164 assert(set != NULL);
165
166 *set = UINT32_MAX;
167 return 0;
168}
169
170/**
171 *
172 * @param set
173 * @param signo
174 * @return
175 */
176int posix_sigaddset(posix_sigset_t *set, int signo)
177{
178 assert(set != NULL);
179
180 *set |= (1 << signo);
181 return 0;
182}
183
184/**
185 *
186 * @param set
187 * @param signo
188 * @return
189 */
190int posix_sigdelset(posix_sigset_t *set, int signo)
191{
192 assert(set != NULL);
193
194 *set &= ~(1 << signo);
195 return 0;
196}
197
198/**
199 *
200 * @param set
201 * @param signo
202 * @return
203 */
204int posix_sigismember(const posix_sigset_t *set, int signo)
205{
206 assert(set != NULL);
207
208 return (*set & (1 << signo)) != 0;
209}
210
211/**
212 *
213 * @param sig
214 * @param act
215 * @param oact
216 */
217static void _sigaction_unsafe(int sig, const struct posix_sigaction *restrict act,
218 struct posix_sigaction *restrict oact)
219{
220 if (oact != NULL) {
221 memcpy(oact, &_signal_actions[sig],
222 sizeof(struct posix_sigaction));
223 }
224
225 if (act != NULL) {
226 memcpy(&_signal_actions[sig], act,
227 sizeof(struct posix_sigaction));
228 }
229}
230
231/**
232 *
233 * @param sig
234 * @param act
235 * @param oact
236 * @return
237 */
238int posix_sigaction(int sig, const struct posix_sigaction *restrict act,
239 struct posix_sigaction *restrict oact)
240{
241 if (sig > _TOP_SIGNAL || (act != NULL &&
242 (sig == SIGKILL || sig == SIGSTOP))) {
243 errno = EINVAL;
244 return -1;
245 }
246
247 if (sig > _TOP_CATCHABLE_SIGNAL) {
248 posix_psignal(sig,
249 "WARNING: registering handler for a partially"
250 " or fully unsupported signal. This handler may only be"
251 " invoked by the raise() function, which may not be what"
252 " the application developer intended.\nSignal name");
253 }
254
255 fibril_mutex_lock(&_signal_mutex);
256 _sigaction_unsafe(sig, act, oact);
257 fibril_mutex_unlock(&_signal_mutex);
258
259 return 0;
260}
261
262/**
263 *
264 * @param sig
265 * @param func
266 * @return
267 */
268void (*posix_signal(int sig, void (*func)(int)))(int)
269{
270 struct posix_sigaction new = {
271 .sa_handler = func,
272 .sa_mask = 0,
273 .sa_flags = 0,
274 .sa_sigaction = NULL
275 };
276 struct posix_sigaction old;
277 if (posix_sigaction(sig, func == NULL ? NULL : &new, &old) == 0) {
278 return old.sa_handler;
279 } else {
280 return SIG_ERR;
281 }
282}
283
284/**
285 *
286 * @param signo
287 * @param siginfo
288 * @return
289 */
290static int _raise_sigaction(int signo, posix_siginfo_t *siginfo)
291{
292 assert(signo >= 0 && signo <= _TOP_SIGNAL);
293 assert(siginfo != NULL);
294
295 fibril_mutex_lock(&_signal_mutex);
296
297 struct posix_sigaction action = _signal_actions[signo];
298
299 if (posix_sigismember(&_signal_mask, signo) ||
300 action.sa_handler == SIG_HOLD) {
301 // TODO: queue signal
302 fibril_mutex_unlock(&_signal_mutex);
303 return -1;
304 }
305
306 /* Modifying signal mask is unnecessary,
307 * signal handling is serialized.
308 */
309
310 if ((action.sa_flags & SA_RESETHAND) && signo != SIGILL && signo != SIGTRAP) {
311 _signal_actions[signo] = (struct posix_sigaction) DEFAULT_HANDLER;
312 };
313
314 if (action.sa_flags & SA_SIGINFO) {
315 assert(action.sa_sigaction != NULL);
316 action.sa_sigaction(signo, siginfo, NULL);
317 } else {
318 assert(action.sa_handler != NULL);
319 action.sa_handler(signo);
320 }
321
322 fibril_mutex_unlock(&_signal_mutex);
323
324 return 0;
325}
326
327/**
328 *
329 * @param sig
330 * @return
331 */
332int posix_raise(int sig)
333{
334 if (sig >= 0 && sig <= _TOP_SIGNAL) {
335 posix_siginfo_t siginfo = {
336 .si_signo = sig,
337 .si_code = SI_USER
338 };
339 return _raise_sigaction(sig, &siginfo);
340 } else {
341 errno = EINVAL;
342 return -1;
343 }
344}
345
346/**
347 *
348 * @param pid
349 * @param signo
350 * @return
351 */
352int posix_kill(posix_pid_t pid, int signo)
353{
354 if (pid < 1) {
355 // TODO
356 errno = ENOTSUP;
357 return -1;
358 }
359
360 if (pid == (posix_pid_t) task_get_id()) {
361 return posix_raise(signo);
362 }
363
364 if (pid > _TOP_SIGNAL) {
365 errno = EINVAL;
366 return -1;
367 }
368
369 switch (signo) {
370 case SIGKILL:
371 task_kill(pid);
372 break;
373 default:
374 /* Nothing else supported yet. */
375 errno = ENOTSUP;
376 return -1;
377 }
378
379 return 0;
380}
381
382/**
383 *
384 * @param pid
385 * @param sig
386 * @return
387 */
388int posix_killpg(posix_pid_t pid, int sig)
389{
390 assert(pid > 1);
391 return posix_kill(-pid, sig);
392}
393
394/**
395 *
396 * @param pinfo
397 * @param message
398 */
399void posix_psiginfo(const posix_siginfo_t *pinfo, const char *message)
400{
401 assert(pinfo != NULL);
402 posix_psignal(pinfo->si_signo, message);
403 // TODO: print si_code
404}
405
406/**
407 *
408 * @param signum
409 * @param message
410 */
411void posix_psignal(int signum, const char *message)
412{
413 char *sigmsg = posix_strsignal(signum);
414 if (message == NULL || *message == '\0') {
415 fprintf(stderr, "%s\n", sigmsg);
416 } else {
417 fprintf(stderr, "%s: %s\n", message, sigmsg);
418 }
419}
420
421/**
422 *
423 * @param how
424 * @param set
425 * @param oset
426 * @return
427 */
428int posix_thread_sigmask(int how, const posix_sigset_t *restrict set,
429 posix_sigset_t *restrict oset)
430{
431 fibril_mutex_lock(&_signal_mutex);
432
433 if (oset != NULL) {
434 *oset = _signal_mask;
435 }
436 if (set != NULL) {
437 switch (how) {
438 case SIG_BLOCK:
439 _signal_mask |= *set;
440 break;
441 case SIG_UNBLOCK:
442 _signal_mask &= ~*set;
443 break;
444 case SIG_SETMASK:
445 _signal_mask = *set;
446 break;
447 default:
448 fibril_mutex_unlock(&_signal_mutex);
449 return EINVAL;
450 }
451 }
452
453 // TODO: queued signal handling
454
455 fibril_mutex_unlock(&_signal_mutex);
456
457 return 0;
458}
459
460/**
461 *
462 * @param how
463 * @param set
464 * @param oset
465 * @return
466 */
467int posix_sigprocmask(int how, const posix_sigset_t *restrict set,
468 posix_sigset_t *restrict oset)
469{
470 int result = posix_thread_sigmask(how, set, oset);
471 if (result != 0) {
472 errno = result;
473 return -1;
474 }
475 return 0;
476}
477
478/** @}
479 */
Note: See TracBrowser for help on using the repository browser.