source: mainline/uspace/lib/posix/src/signal.c@ 7570a95f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 7570a95f was 09ab0a9a, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Fix vertical spacing with new Ccheck revision.

  • Property mode set to 100644
File size: 13.3 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
[a3da2b2]35#include "posix/signal.h"
[7530a00]36#include "internal/common.h"
[a3da2b2]37#include "posix/limits.h"
38#include "posix/stdlib.h"
39#include "posix/string.h"
[0d0b319]40
41#include <errno.h>
[d3ce33fa]42
43#include "libc/fibril_synch.h"
44#include "libc/task.h"
45
[7c3fb9b]46/*
47 * This file implements a fairly dumb and incomplete "simulation" of
[4419c34]48 * POSIX signals. Since HelenOS doesn't support signals and mostly doesn't
49 * have any equivalent functionality, most of the signals are useless. The
50 * main purpose of this implementation is thus to help port applications using
51 * signals with minimal modification, but if the application uses signals for
52 * anything non-trivial, it's quite probable it won't work properly even if
53 * it builds without problems.
54 */
[4cf8ca6]55
[d3ce33fa]56/* Used to serialize signal handling. */
57static FIBRIL_MUTEX_INITIALIZE(_signal_mutex);
58
[4419c34]59static LIST_INITIALIZE(_signal_queue);
60
[7f9df7b9]61static sigset_t _signal_mask = 0;
[d3ce33fa]62
63#define DEFAULT_HANDLER { .sa_handler = SIG_DFL, \
64 .sa_mask = 0, .sa_flags = 0, .sa_sigaction = NULL }
65
[4419c34]66/* Actions associated with each signal number. */
[7f9df7b9]67static struct sigaction _signal_actions[_TOP_SIGNAL + 1] = {
[1b20da0]68 DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER,
69 DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER,
70 DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER,
71 DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER,
72 DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER,
73 DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER,
[d3ce33fa]74 DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER
75};
76
[4cf8ca6]77/**
[f215bb5f]78 * Default signal handler. Executes the default action for each signal,
79 * as reasonable within HelenOS.
80 *
81 * @param signo Signal number.
[4cf8ca6]82 */
[d3ce33fa]83void __posix_default_signal_handler(int signo)
84{
85 switch (signo) {
86 case SIGABRT:
87 abort();
88 case SIGQUIT:
[f215bb5f]89 fprintf(stderr, "Quit signal raised. Exiting.\n");
[d3ce33fa]90 exit(EXIT_FAILURE);
91 case SIGINT:
[f215bb5f]92 fprintf(stderr, "Interrupt signal caught. Exiting.\n");
[d3ce33fa]93 exit(EXIT_FAILURE);
94 case SIGTERM:
[f215bb5f]95 fprintf(stderr, "Termination signal caught. Exiting.\n");
[d3ce33fa]96 exit(EXIT_FAILURE);
97 case SIGSTOP:
[f215bb5f]98 fprintf(stderr, "Stop signal caught, but unsupported. Ignoring.\n");
[d3ce33fa]99 break;
100 case SIGKILL:
101 /* This will only occur when raise or similar is called. */
102 /* Commit suicide. */
103 task_kill(task_get_id());
[a35b458]104
[d3ce33fa]105 /* Should not be reached. */
106 abort();
107 case SIGFPE:
108 case SIGBUS:
109 case SIGILL:
110 case SIGSEGV:
[7f9df7b9]111 psignal(signo, "Hardware exception raised by user code");
[d3ce33fa]112 abort();
113 case SIGSYS:
114 case SIGXCPU:
115 case SIGXFSZ:
116 case SIGTRAP:
117 case SIGHUP:
118 case SIGPIPE:
119 case SIGPOLL:
120 case SIGURG:
121 case SIGTSTP:
122 case SIGTTIN:
123 case SIGTTOU:
[7f9df7b9]124 psignal(signo, "Unsupported signal caught");
[d3ce33fa]125 abort();
126 case SIGCHLD:
127 case SIGUSR1:
128 case SIGUSR2:
129 case SIGALRM:
130 case SIGVTALRM:
131 case SIGPROF:
132 case SIGCONT:
133 /* ignored */
134 break;
135 }
136}
137
[55b1efd]138/**
139 * Just an empty function to get an unique pointer value for comparison.
[4cf8ca6]140 *
[55b1efd]141 * @param signo Signal number.
[4cf8ca6]142 */
[d3ce33fa]143void __posix_hold_signal_handler(int signo)
144{
145 /* Nothing */
146}
147
[55b1efd]148/**
149 * Empty function to be used as ignoring handler.
[1b20da0]150 *
[55b1efd]151 * @param signo Signal number.
[4cf8ca6]152 */
[d3ce33fa]153void __posix_ignore_signal_handler(int signo)
154{
155 /* Nothing */
156}
157
[55b1efd]158/**
159 * Clear the signal set.
[1b20da0]160 *
[4419c34]161 * @param set Pointer to the signal set.
162 * @return Always returns zero.
[4cf8ca6]163 */
[7f9df7b9]164int sigemptyset(sigset_t *set)
[d3ce33fa]165{
166 assert(set != NULL);
167
168 *set = 0;
169 return 0;
170}
171
[55b1efd]172/**
173 * Fill the signal set (i.e. add all signals).
[1b20da0]174 *
[4419c34]175 * @param set Pointer to the signal set.
176 * @return Always returns zero.
[4cf8ca6]177 */
[7f9df7b9]178int sigfillset(sigset_t *set)
[d3ce33fa]179{
180 assert(set != NULL);
181
182 *set = UINT32_MAX;
183 return 0;
184}
185
[55b1efd]186/**
187 * Add a signal to the set.
[1b20da0]188 *
[4419c34]189 * @param set Pointer to the signal set.
190 * @param signo Signal number to add.
191 * @return Always returns zero.
[4cf8ca6]192 */
[7f9df7b9]193int sigaddset(sigset_t *set, int signo)
[d3ce33fa]194{
195 assert(set != NULL);
196
197 *set |= (1 << signo);
198 return 0;
199}
200
[55b1efd]201/**
202 * Delete a signal from the set.
[1b20da0]203 *
[4419c34]204 * @param set Pointer to the signal set.
205 * @param signo Signal number to remove.
206 * @return Always returns zero.
[4cf8ca6]207 */
[7f9df7b9]208int sigdelset(sigset_t *set, int signo)
[d3ce33fa]209{
210 assert(set != NULL);
211
212 *set &= ~(1 << signo);
213 return 0;
214}
215
[55b1efd]216/**
217 * Inclusion test for a signal set.
[1b20da0]218 *
[4419c34]219 * @param set Pointer to the signal set.
220 * @param signo Signal number to query.
221 * @return 1 if the signal is in the set, 0 otherwise.
[4cf8ca6]222 */
[7f9df7b9]223int sigismember(const sigset_t *set, int signo)
[d3ce33fa]224{
225 assert(set != NULL);
[a35b458]226
[d3ce33fa]227 return (*set & (1 << signo)) != 0;
228}
229
[55b1efd]230/**
231 * Unsafe variant of the sigaction() function.
232 * Doesn't do any checking of its arguments and
233 * does not deal with thread-safety.
[1b20da0]234 *
[4cf8ca6]235 * @param sig
236 * @param act
237 * @param oact
238 */
[7f9df7b9]239static void _sigaction_unsafe(int sig, const struct sigaction *restrict act,
240 struct sigaction *restrict oact)
[d3ce33fa]241{
242 if (oact != NULL) {
243 memcpy(oact, &_signal_actions[sig],
[7f9df7b9]244 sizeof(struct sigaction));
[d3ce33fa]245 }
246
247 if (act != NULL) {
248 memcpy(&_signal_actions[sig], act,
[7f9df7b9]249 sizeof(struct sigaction));
[d3ce33fa]250 }
251}
252
[55b1efd]253/**
254 * Sets a new action for the given signal number.
[1b20da0]255 *
[4419c34]256 * @param sig Signal number to set action for.
257 * @param act If not NULL, contents of this structure are
258 * used as the new action for the signal.
259 * @param oact If not NULL, the original action associated with the signal
[1b20da0]260 * is stored in the structure pointer to.
[4419c34]261 * @return -1 with errno set on failure, 0 on success.
[4cf8ca6]262 */
[7f9df7b9]263int sigaction(int sig, const struct sigaction *restrict act,
264 struct sigaction *restrict oact)
[d3ce33fa]265{
266 if (sig > _TOP_SIGNAL || (act != NULL &&
267 (sig == SIGKILL || sig == SIGSTOP))) {
268 errno = EINVAL;
269 return -1;
270 }
271
272 if (sig > _TOP_CATCHABLE_SIGNAL) {
[7f9df7b9]273 psignal(sig,
[d3ce33fa]274 "WARNING: registering handler for a partially"
275 " or fully unsupported signal. This handler may only be"
276 " invoked by the raise() function, which may not be what"
[ffff746]277 " the application developer intended");
[d3ce33fa]278 }
279
280 fibril_mutex_lock(&_signal_mutex);
281 _sigaction_unsafe(sig, act, oact);
282 fibril_mutex_unlock(&_signal_mutex);
283
284 return 0;
285}
[7530a00]286
[55b1efd]287/**
288 * Sets a new handler for the given signal number.
[1b20da0]289 *
[4419c34]290 * @param sig Signal number to set handler for.
291 * @param func Handler function.
292 * @return SIG_ERR on failure, original handler on success.
[4cf8ca6]293 */
[7f9df7b9]294void (*signal(int sig, void (*func)(int)))(int)
[7530a00]295{
[7f9df7b9]296 struct sigaction new = {
[d3ce33fa]297 .sa_handler = func,
298 .sa_mask = 0,
299 .sa_flags = 0,
300 .sa_sigaction = NULL
301 };
[7f9df7b9]302 struct sigaction old;
303 if (sigaction(sig, func == NULL ? NULL : &new, &old) == 0) {
[d3ce33fa]304 return old.sa_handler;
305 } else {
306 return SIG_ERR;
307 }
308}
309
[4419c34]310typedef struct {
311 link_t link;
312 int signo;
[7f9df7b9]313 siginfo_t siginfo;
[4419c34]314} signal_queue_item;
315
[55b1efd]316/**
317 * Queue blocked signal.
[4419c34]318 *
319 * @param signo Signal number.
320 * @param siginfo Additional information about the signal.
321 */
[7f9df7b9]322static void _queue_signal(int signo, siginfo_t *siginfo)
[4419c34]323{
324 assert(signo >= 0 && signo <= _TOP_SIGNAL);
325 assert(siginfo != NULL);
[a35b458]326
[4419c34]327 signal_queue_item *item = malloc(sizeof(signal_queue_item));
328 link_initialize(&(item->link));
329 item->signo = signo;
[7f9df7b9]330 memcpy(&item->siginfo, siginfo, sizeof(siginfo_t));
[4419c34]331 list_append(&(item->link), &_signal_queue);
332}
333
[55b1efd]334/**
335 * Executes an action associated with the given signal.
[4419c34]336 *
337 * @param signo Signal number.
338 * @param siginfo Additional information about the circumstances of this raise.
339 * @return 0 if the action has been successfully executed. -1 if the signal is
340 * blocked.
[4cf8ca6]341 */
[7f9df7b9]342static int _raise_sigaction(int signo, siginfo_t *siginfo)
[d3ce33fa]343{
344 assert(signo >= 0 && signo <= _TOP_SIGNAL);
345 assert(siginfo != NULL);
346
347 fibril_mutex_lock(&_signal_mutex);
348
[7f9df7b9]349 struct sigaction action = _signal_actions[signo];
[d3ce33fa]350
[7f9df7b9]351 if (sigismember(&_signal_mask, signo) ||
[d3ce33fa]352 action.sa_handler == SIG_HOLD) {
[4419c34]353 _queue_signal(signo, siginfo);
[d3ce33fa]354 fibril_mutex_unlock(&_signal_mutex);
355 return -1;
356 }
357
[7c3fb9b]358 /*
359 * Modifying signal mask is unnecessary,
[d3ce33fa]360 * signal handling is serialized.
361 */
362
363 if ((action.sa_flags & SA_RESETHAND) && signo != SIGILL && signo != SIGTRAP) {
[7f9df7b9]364 _signal_actions[signo] = (struct sigaction) DEFAULT_HANDLER;
[2aadf2b]365 }
[d3ce33fa]366
367 if (action.sa_flags & SA_SIGINFO) {
368 assert(action.sa_sigaction != NULL);
369 action.sa_sigaction(signo, siginfo, NULL);
370 } else {
371 assert(action.sa_handler != NULL);
372 action.sa_handler(signo);
373 }
374
375 fibril_mutex_unlock(&_signal_mutex);
376
377 return 0;
[7530a00]378}
379
[55b1efd]380/**
381 * Raise all unblocked previously queued signals.
[4419c34]382 */
[193d280c]383static void _dequeue_unblocked_signals(void)
[4419c34]384{
385 link_t *iterator = _signal_queue.head.next;
386 link_t *next;
[a35b458]387
[4419c34]388 while (iterator != &(_signal_queue).head) {
389 next = iterator->next;
[a35b458]390
[4419c34]391 signal_queue_item *item =
392 list_get_instance(iterator, signal_queue_item, link);
[a35b458]393
[7f9df7b9]394 if (!sigismember(&_signal_mask, item->signo) &&
[4419c34]395 _signal_actions[item->signo].sa_handler != SIG_HOLD) {
396 list_remove(&(item->link));
397 _raise_sigaction(item->signo, &(item->siginfo));
398 free(item);
399 }
[a35b458]400
[4419c34]401 iterator = next;
402 }
403}
404
[55b1efd]405/**
406 * Raise a signal for the calling process.
[1b20da0]407 *
[4419c34]408 * @param sig Signal number.
409 * @return -1 with errno set on failure, 0 on success.
[4cf8ca6]410 */
[7f9df7b9]411int raise(int sig)
[7530a00]412{
[d3ce33fa]413 if (sig >= 0 && sig <= _TOP_SIGNAL) {
[7f9df7b9]414 siginfo_t siginfo = {
[d3ce33fa]415 .si_signo = sig,
416 .si_code = SI_USER
417 };
418 return _raise_sigaction(sig, &siginfo);
419 } else {
420 errno = EINVAL;
421 return -1;
422 }
[7530a00]423}
424
[55b1efd]425/**
426 * Raises a signal for a selected process.
[1b20da0]427 *
[4419c34]428 * @param pid PID of the process for which the signal shall be raised.
429 * @param signo Signal to raise.
430 * @return -1 with errno set on failure (possible errors include unsupported
431 * action, invalid signal number, lack of permissions, etc.), 0 on success.
[4cf8ca6]432 */
[7f9df7b9]433int kill(pid_t pid, int signo)
[7530a00]434{
[d3ce33fa]435 if (pid < 1) {
436 // TODO
437 errno = ENOTSUP;
438 return -1;
439 }
440
[ffff746]441 if (signo > _TOP_SIGNAL) {
[d3ce33fa]442 errno = EINVAL;
443 return -1;
444 }
445
[7f9df7b9]446 if (pid == (pid_t) task_get_id()) {
447 return raise(signo);
[ffff746]448 }
449
[d3ce33fa]450 switch (signo) {
451 case SIGKILL:
452 task_kill(pid);
453 break;
454 default:
455 /* Nothing else supported yet. */
456 errno = ENOTSUP;
457 return -1;
458 }
459
460 return 0;
[7530a00]461}
462
[55b1efd]463/**
464 * Send a signal to a process group. Always fails at the moment because of
465 * lack of this functionality in HelenOS.
[1b20da0]466 *
[4419c34]467 * @param pid PID of the process group.
468 * @param sig Signal number.
469 * @return -1 on failure, 0 on success (see kill()).
[4cf8ca6]470 */
[7f9df7b9]471int killpg(pid_t pid, int sig)
[244d6fd]472{
[d3ce33fa]473 assert(pid > 1);
[7f9df7b9]474 return kill(-pid, sig);
[244d6fd]475}
476
[55b1efd]477/**
478 * Outputs information about the signal to the standard error stream.
[1b20da0]479 *
[4419c34]480 * @param pinfo SigInfo struct to write.
481 * @param message String to output alongside human-readable signal description.
[4cf8ca6]482 */
[7f9df7b9]483void psiginfo(const siginfo_t *pinfo, const char *message)
[d3ce33fa]484{
485 assert(pinfo != NULL);
[7f9df7b9]486 psignal(pinfo->si_signo, message);
[d3ce33fa]487 // TODO: print si_code
488}
489
[55b1efd]490/**
491 * Outputs information about the signal to the standard error stream.
[1b20da0]492 *
[4419c34]493 * @param signum Signal number.
494 * @param message String to output alongside human-readable signal description.
[4cf8ca6]495 */
[7f9df7b9]496void psignal(int signum, const char *message)
[d3ce33fa]497{
[7f9df7b9]498 char *sigmsg = strsignal(signum);
[d3ce33fa]499 if (message == NULL || *message == '\0') {
500 fprintf(stderr, "%s\n", sigmsg);
501 } else {
502 fprintf(stderr, "%s: %s\n", message, sigmsg);
503 }
504}
505
[55b1efd]506/**
507 * Manipulate the signal mask of the calling thread.
[1b20da0]508 *
[4419c34]509 * @param how What to do with the mask.
510 * @param set Signal set to work with.
511 * @param oset If not NULL, the original signal mask is coppied here.
512 * @return 0 success, errorcode on failure.
[4cf8ca6]513 */
[7f9df7b9]514int thread_sigmask(int how, const sigset_t *restrict set,
515 sigset_t *restrict oset)
[7530a00]516{
[d3ce33fa]517 fibril_mutex_lock(&_signal_mutex);
518
519 if (oset != NULL) {
520 *oset = _signal_mask;
521 }
522 if (set != NULL) {
523 switch (how) {
524 case SIG_BLOCK:
525 _signal_mask |= *set;
526 break;
527 case SIG_UNBLOCK:
528 _signal_mask &= ~*set;
529 break;
530 case SIG_SETMASK:
531 _signal_mask = *set;
532 break;
533 default:
534 fibril_mutex_unlock(&_signal_mutex);
535 return EINVAL;
536 }
537 }
[a35b458]538
[4419c34]539 _dequeue_unblocked_signals();
[d3ce33fa]540
541 fibril_mutex_unlock(&_signal_mutex);
542
543 return 0;
[7530a00]544}
545
[55b1efd]546/**
547 * Manipulate the signal mask of the process.
[1b20da0]548 *
[4419c34]549 * @param how What to do with the mask.
550 * @param set Signal set to work with.
551 * @param oset If not NULL, the original signal mask is coppied here.
552 * @return 0 on success, -1 with errno set on failure.
[4cf8ca6]553 */
[7f9df7b9]554int sigprocmask(int how, const sigset_t *restrict set,
555 sigset_t *restrict oset)
[7530a00]556{
[7f9df7b9]557 int result = thread_sigmask(how, set, oset);
[d3ce33fa]558 if (result != 0) {
559 errno = result;
560 return -1;
561 }
562 return 0;
[7530a00]563}
564
565/** @}
566 */
Note: See TracBrowser for help on using the repository browser.