source: mainline/uspace/lib/posix/src/signal.c@ 3061bc1

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

style: Remove trailing whitespace on non-empty lines, in certain file types.

Command used: tools/srepl '\([^[:space:]]\)\s\+$' '\1' -- *.c *.h *.py *.sh *.s *.S *.ag

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