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
RevLine 
[7530a00]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 */
[4cf8ca6]32/** @file Signal handling.
[7530a00]33 */
34
35#define LIBPOSIX_INTERNAL
36
37#include "signal.h"
38#include "internal/common.h"
[d3ce33fa]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
[4cf8ca6]47// TODO: documentation
48
[d3ce33fa]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
[4cf8ca6]67/**
68 *
69 * @param signo
70 */
[d3ce33fa]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
[4cf8ca6]126/**
127 *
128 * @param signo
129 */
[d3ce33fa]130void __posix_hold_signal_handler(int signo)
131{
132 /* Nothing */
133}
134
[4cf8ca6]135/**
136 *
137 * @param signo
138 */
[d3ce33fa]139void __posix_ignore_signal_handler(int signo)
140{
141 /* Nothing */
142}
143
[4cf8ca6]144/**
145 *
146 * @param set
147 * @return
148 */
[d3ce33fa]149int posix_sigemptyset(posix_sigset_t *set)
150{
151 assert(set != NULL);
152
153 *set = 0;
154 return 0;
155}
156
[4cf8ca6]157/**
158 *
159 * @param set
160 * @return
161 */
[d3ce33fa]162int posix_sigfillset(posix_sigset_t *set)
163{
164 assert(set != NULL);
165
166 *set = UINT32_MAX;
167 return 0;
168}
169
[4cf8ca6]170/**
171 *
172 * @param set
173 * @param signo
174 * @return
175 */
[d3ce33fa]176int posix_sigaddset(posix_sigset_t *set, int signo)
177{
178 assert(set != NULL);
179
180 *set |= (1 << signo);
181 return 0;
182}
183
[4cf8ca6]184/**
185 *
186 * @param set
187 * @param signo
188 * @return
189 */
[d3ce33fa]190int posix_sigdelset(posix_sigset_t *set, int signo)
191{
192 assert(set != NULL);
193
194 *set &= ~(1 << signo);
195 return 0;
196}
197
[4cf8ca6]198/**
199 *
200 * @param set
201 * @param signo
202 * @return
203 */
[d3ce33fa]204int posix_sigismember(const posix_sigset_t *set, int signo)
205{
206 assert(set != NULL);
207
208 return (*set & (1 << signo)) != 0;
209}
210
[4cf8ca6]211/**
212 *
213 * @param sig
214 * @param act
215 * @param oact
216 */
[d3ce33fa]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
[4cf8ca6]231/**
232 *
233 * @param sig
234 * @param act
235 * @param oact
236 * @return
237 */
[d3ce33fa]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}
[7530a00]261
[4cf8ca6]262/**
263 *
264 * @param sig
265 * @param func
266 * @return
267 */
[7530a00]268void (*posix_signal(int sig, void (*func)(int)))(int)
269{
[d3ce33fa]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
[4cf8ca6]284/**
285 *
286 * @param signo
287 * @param siginfo
288 * @return
289 */
[d3ce33fa]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;
[7530a00]325}
326
[4cf8ca6]327/**
328 *
329 * @param sig
330 * @return
331 */
[7530a00]332int posix_raise(int sig)
333{
[d3ce33fa]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 }
[7530a00]344}
345
[4cf8ca6]346/**
347 *
348 * @param pid
349 * @param signo
350 * @return
351 */
[d3ce33fa]352int posix_kill(posix_pid_t pid, int signo)
[7530a00]353{
[d3ce33fa]354 if (pid < 1) {
355 // TODO
356 errno = ENOTSUP;
357 return -1;
358 }
359
[1757edbd]360 if (pid == (posix_pid_t) task_get_id()) {
[d3ce33fa]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;
[7530a00]380}
381
[4cf8ca6]382/**
383 *
384 * @param pid
385 * @param sig
386 * @return
387 */
[d3ce33fa]388int posix_killpg(posix_pid_t pid, int sig)
[244d6fd]389{
[d3ce33fa]390 assert(pid > 1);
391 return posix_kill(-pid, sig);
[244d6fd]392}
393
[4cf8ca6]394/**
395 *
396 * @param pinfo
397 * @param message
398 */
[d3ce33fa]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
[4cf8ca6]406/**
407 *
408 * @param signum
409 * @param message
410 */
[d3ce33fa]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
[4cf8ca6]421/**
422 *
423 * @param how
424 * @param set
425 * @param oset
426 * @return
427 */
[d3ce33fa]428int posix_thread_sigmask(int how, const posix_sigset_t *restrict set,
429 posix_sigset_t *restrict oset)
[7530a00]430{
[d3ce33fa]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;
[7530a00]458}
459
[4cf8ca6]460/**
461 *
462 * @param how
463 * @param set
464 * @param oset
465 * @return
466 */
[7530a00]467int posix_sigprocmask(int how, const posix_sigset_t *restrict set,
468 posix_sigset_t *restrict oset)
469{
[d3ce33fa]470 int result = posix_thread_sigmask(how, set, oset);
471 if (result != 0) {
472 errno = result;
473 return -1;
474 }
475 return 0;
[7530a00]476}
477
478/** @}
479 */
Note: See TracBrowser for help on using the repository browser.