source: mainline/uspace/lib/posix/signal.c@ f215bb5f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f215bb5f was f215bb5f, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 14 years ago

Various little changes.

  • Property mode set to 100644
File size: 9.3 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 * Default signal handler. Executes the default action for each signal,
69 * as reasonable within HelenOS.
70 *
71 * @param signo Signal number.
72 */
73void __posix_default_signal_handler(int signo)
74{
75 switch (signo) {
76 case SIGABRT:
77 abort();
78 case SIGQUIT:
79 fprintf(stderr, "Quit signal raised. Exiting.\n");
80 exit(EXIT_FAILURE);
81 case SIGINT:
82 fprintf(stderr, "Interrupt signal caught. Exiting.\n");
83 exit(EXIT_FAILURE);
84 case SIGTERM:
85 fprintf(stderr, "Termination signal caught. Exiting.\n");
86 exit(EXIT_FAILURE);
87 case SIGSTOP:
88 fprintf(stderr, "Stop signal caught, but unsupported. Ignoring.\n");
89 break;
90 case SIGKILL:
91 /* This will only occur when raise or similar is called. */
92 /* Commit suicide. */
93 task_kill(task_get_id());
94
95 /* Should not be reached. */
96 abort();
97 case SIGFPE:
98 case SIGBUS:
99 case SIGILL:
100 case SIGSEGV:
101 posix_psignal(signo, "Hardware exception raised by user code");
102 abort();
103 case SIGSYS:
104 case SIGXCPU:
105 case SIGXFSZ:
106 case SIGTRAP:
107 case SIGHUP:
108 case SIGPIPE:
109 case SIGPOLL:
110 case SIGURG:
111 case SIGTSTP:
112 case SIGTTIN:
113 case SIGTTOU:
114 posix_psignal(signo, "Unsupported signal caught");
115 abort();
116 case SIGCHLD:
117 case SIGUSR1:
118 case SIGUSR2:
119 case SIGALRM:
120 case SIGVTALRM:
121 case SIGPROF:
122 case SIGCONT:
123 /* ignored */
124 break;
125 }
126}
127
128/**
129 *
130 * @param signo
131 */
132void __posix_hold_signal_handler(int signo)
133{
134 /* Nothing */
135}
136
137/**
138 *
139 * @param signo
140 */
141void __posix_ignore_signal_handler(int signo)
142{
143 /* Nothing */
144}
145
146/**
147 *
148 * @param set
149 * @return
150 */
151int posix_sigemptyset(posix_sigset_t *set)
152{
153 assert(set != NULL);
154
155 *set = 0;
156 return 0;
157}
158
159/**
160 *
161 * @param set
162 * @return
163 */
164int posix_sigfillset(posix_sigset_t *set)
165{
166 assert(set != NULL);
167
168 *set = UINT32_MAX;
169 return 0;
170}
171
172/**
173 *
174 * @param set
175 * @param signo
176 * @return
177 */
178int posix_sigaddset(posix_sigset_t *set, int signo)
179{
180 assert(set != NULL);
181
182 *set |= (1 << signo);
183 return 0;
184}
185
186/**
187 *
188 * @param set
189 * @param signo
190 * @return
191 */
192int posix_sigdelset(posix_sigset_t *set, int signo)
193{
194 assert(set != NULL);
195
196 *set &= ~(1 << signo);
197 return 0;
198}
199
200/**
201 *
202 * @param set
203 * @param signo
204 * @return
205 */
206int posix_sigismember(const posix_sigset_t *set, int signo)
207{
208 assert(set != NULL);
209
210 return (*set & (1 << signo)) != 0;
211}
212
213/**
214 *
215 * @param sig
216 * @param act
217 * @param oact
218 */
219static void _sigaction_unsafe(int sig, const struct posix_sigaction *restrict act,
220 struct posix_sigaction *restrict oact)
221{
222 if (oact != NULL) {
223 memcpy(oact, &_signal_actions[sig],
224 sizeof(struct posix_sigaction));
225 }
226
227 if (act != NULL) {
228 memcpy(&_signal_actions[sig], act,
229 sizeof(struct posix_sigaction));
230 }
231}
232
233/**
234 *
235 * @param sig
236 * @param act
237 * @param oact
238 * @return
239 */
240int posix_sigaction(int sig, const struct posix_sigaction *restrict act,
241 struct posix_sigaction *restrict oact)
242{
243 if (sig > _TOP_SIGNAL || (act != NULL &&
244 (sig == SIGKILL || sig == SIGSTOP))) {
245 errno = EINVAL;
246 return -1;
247 }
248
249 if (sig > _TOP_CATCHABLE_SIGNAL) {
250 posix_psignal(sig,
251 "WARNING: registering handler for a partially"
252 " or fully unsupported signal. This handler may only be"
253 " invoked by the raise() function, which may not be what"
254 " the application developer intended.\nSignal name");
255 }
256
257 fibril_mutex_lock(&_signal_mutex);
258 _sigaction_unsafe(sig, act, oact);
259 fibril_mutex_unlock(&_signal_mutex);
260
261 return 0;
262}
263
264/**
265 *
266 * @param sig
267 * @param func
268 * @return
269 */
270void (*posix_signal(int sig, void (*func)(int)))(int)
271{
272 struct posix_sigaction new = {
273 .sa_handler = func,
274 .sa_mask = 0,
275 .sa_flags = 0,
276 .sa_sigaction = NULL
277 };
278 struct posix_sigaction old;
279 if (posix_sigaction(sig, func == NULL ? NULL : &new, &old) == 0) {
280 return old.sa_handler;
281 } else {
282 return SIG_ERR;
283 }
284}
285
286/**
287 *
288 * @param signo
289 * @param siginfo
290 * @return
291 */
292static int _raise_sigaction(int signo, posix_siginfo_t *siginfo)
293{
294 assert(signo >= 0 && signo <= _TOP_SIGNAL);
295 assert(siginfo != NULL);
296
297 fibril_mutex_lock(&_signal_mutex);
298
299 struct posix_sigaction action = _signal_actions[signo];
300
301 if (posix_sigismember(&_signal_mask, signo) ||
302 action.sa_handler == SIG_HOLD) {
303 // TODO: queue signal
304 fibril_mutex_unlock(&_signal_mutex);
305 return -1;
306 }
307
308 /* Modifying signal mask is unnecessary,
309 * signal handling is serialized.
310 */
311
312 if ((action.sa_flags & SA_RESETHAND) && signo != SIGILL && signo != SIGTRAP) {
313 _signal_actions[signo] = (struct posix_sigaction) DEFAULT_HANDLER;
314 };
315
316 if (action.sa_flags & SA_SIGINFO) {
317 assert(action.sa_sigaction != NULL);
318 action.sa_sigaction(signo, siginfo, NULL);
319 } else {
320 assert(action.sa_handler != NULL);
321 action.sa_handler(signo);
322 }
323
324 fibril_mutex_unlock(&_signal_mutex);
325
326 return 0;
327}
328
329/**
330 *
331 * @param sig
332 * @return
333 */
334int posix_raise(int sig)
335{
336 if (sig >= 0 && sig <= _TOP_SIGNAL) {
337 posix_siginfo_t siginfo = {
338 .si_signo = sig,
339 .si_code = SI_USER
340 };
341 return _raise_sigaction(sig, &siginfo);
342 } else {
343 errno = EINVAL;
344 return -1;
345 }
346}
347
348/**
349 *
350 * @param pid
351 * @param signo
352 * @return
353 */
354int posix_kill(posix_pid_t pid, int signo)
355{
356 if (pid < 1) {
357 // TODO
358 errno = ENOTSUP;
359 return -1;
360 }
361
362 if (pid == (posix_pid_t) task_get_id()) {
363 return posix_raise(signo);
364 }
365
366 if (pid > _TOP_SIGNAL) {
367 errno = EINVAL;
368 return -1;
369 }
370
371 switch (signo) {
372 case SIGKILL:
373 task_kill(pid);
374 break;
375 default:
376 /* Nothing else supported yet. */
377 errno = ENOTSUP;
378 return -1;
379 }
380
381 return 0;
382}
383
384/**
385 *
386 * @param pid
387 * @param sig
388 * @return
389 */
390int posix_killpg(posix_pid_t pid, int sig)
391{
392 assert(pid > 1);
393 return posix_kill(-pid, sig);
394}
395
396/**
397 *
398 * @param pinfo
399 * @param message
400 */
401void posix_psiginfo(const posix_siginfo_t *pinfo, const char *message)
402{
403 assert(pinfo != NULL);
404 posix_psignal(pinfo->si_signo, message);
405 // TODO: print si_code
406}
407
408/**
409 *
410 * @param signum
411 * @param message
412 */
413void posix_psignal(int signum, const char *message)
414{
415 char *sigmsg = posix_strsignal(signum);
416 if (message == NULL || *message == '\0') {
417 fprintf(stderr, "%s\n", sigmsg);
418 } else {
419 fprintf(stderr, "%s: %s\n", message, sigmsg);
420 }
421}
422
423/**
424 *
425 * @param how
426 * @param set
427 * @param oset
428 * @return
429 */
430int posix_thread_sigmask(int how, const posix_sigset_t *restrict set,
431 posix_sigset_t *restrict oset)
432{
433 fibril_mutex_lock(&_signal_mutex);
434
435 if (oset != NULL) {
436 *oset = _signal_mask;
437 }
438 if (set != NULL) {
439 switch (how) {
440 case SIG_BLOCK:
441 _signal_mask |= *set;
442 break;
443 case SIG_UNBLOCK:
444 _signal_mask &= ~*set;
445 break;
446 case SIG_SETMASK:
447 _signal_mask = *set;
448 break;
449 default:
450 fibril_mutex_unlock(&_signal_mutex);
451 return EINVAL;
452 }
453 }
454
455 // TODO: queued signal handling
456
457 fibril_mutex_unlock(&_signal_mutex);
458
459 return 0;
460}
461
462/**
463 *
464 * @param how
465 * @param set
466 * @param oset
467 * @return
468 */
469int posix_sigprocmask(int how, const posix_sigset_t *restrict set,
470 posix_sigset_t *restrict oset)
471{
472 int result = posix_thread_sigmask(how, set, oset);
473 if (result != 0) {
474 errno = result;
475 return -1;
476 }
477 return 0;
478}
479
480/** @}
481 */
Note: See TracBrowser for help on using the repository browser.