2
* Copyright (c) 2011 Jiri Zarevucky
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
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.
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.
29
/** @addtogroup libposix
32
/** @file Signal handling.
35
#define LIBPOSIX_INTERNAL
38
#include "internal/common.h"
44
#include "libc/fibril_synch.h"
45
#include "libc/task.h"
47
/* This file implements a fairly dumb and incomplete "simulation" of
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.
56
/* Used to serialize signal handling. */
57
static FIBRIL_MUTEX_INITIALIZE(_signal_mutex);
59
static LIST_INITIALIZE(_signal_queue);
61
static posix_sigset_t _signal_mask = 0;
63
#define DEFAULT_HANDLER { .sa_handler = SIG_DFL, \
64
.sa_mask = 0, .sa_flags = 0, .sa_sigaction = NULL }
66
/* Actions associated with each signal number. */
67
static struct posix_sigaction _signal_actions[_TOP_SIGNAL + 1] = {
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,
74
DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER
78
* Default signal handler. Executes the default action for each signal,
79
* as reasonable within HelenOS.
81
* @param signo Signal number.
83
void __posix_default_signal_handler(int signo)
89
fprintf(stderr, "Quit signal raised. Exiting.\n");
92
fprintf(stderr, "Interrupt signal caught. Exiting.\n");
95
fprintf(stderr, "Termination signal caught. Exiting.\n");
98
fprintf(stderr, "Stop signal caught, but unsupported. Ignoring.\n");
101
/* This will only occur when raise or similar is called. */
102
/* Commit suicide. */
103
task_kill(task_get_id());
105
/* Should not be reached. */
111
posix_psignal(signo, "Hardware exception raised by user code");
124
posix_psignal(signo, "Unsupported signal caught");
139
* Just an empty function to get an unique pointer value for comparison.
141
* @param signo Signal number.
143
void __posix_hold_signal_handler(int signo)
149
* Empty function to be used as ignoring handler.
151
* @param signo Signal number.
153
void __posix_ignore_signal_handler(int signo)
159
* Clear the signal set.
161
* @param set Pointer to the signal set.
162
* @return Always returns zero.
164
int posix_sigemptyset(posix_sigset_t *set)
173
* Fill the signal set (i.e. add all signals).
175
* @param set Pointer to the signal set.
176
* @return Always returns zero.
178
int posix_sigfillset(posix_sigset_t *set)
187
* Add a signal to the set.
189
* @param set Pointer to the signal set.
190
* @param signo Signal number to add.
191
* @return Always returns zero.
193
int posix_sigaddset(posix_sigset_t *set, int signo)
197
*set |= (1 << signo);
202
* Delete a signal from the set.
204
* @param set Pointer to the signal set.
205
* @param signo Signal number to remove.
206
* @return Always returns zero.
208
int posix_sigdelset(posix_sigset_t *set, int signo)
212
*set &= ~(1 << signo);
217
* Inclusion test for a signal set.
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.
223
int posix_sigismember(const posix_sigset_t *set, int signo)
227
return (*set & (1 << signo)) != 0;
231
* Unsafe variant of the sigaction() function.
232
* Doesn't do any checking of its arguments and
233
* does not deal with thread-safety.
239
static void _sigaction_unsafe(int sig, const struct posix_sigaction *restrict act,
240
struct posix_sigaction *restrict oact)
243
memcpy(oact, &_signal_actions[sig],
244
sizeof(struct posix_sigaction));
248
memcpy(&_signal_actions[sig], act,
249
sizeof(struct posix_sigaction));
254
* Sets a new action for the given signal number.
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
260
* is stored in the structure pointer to.
261
* @return -1 with errno set on failure, 0 on success.
263
int posix_sigaction(int sig, const struct posix_sigaction *restrict act,
264
struct posix_sigaction *restrict oact)
266
if (sig > _TOP_SIGNAL || (act != NULL &&
267
(sig == SIGKILL || sig == SIGSTOP))) {
272
if (sig > _TOP_CATCHABLE_SIGNAL) {
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"
277
" the application developer intended");
280
fibril_mutex_lock(&_signal_mutex);
281
_sigaction_unsafe(sig, act, oact);
282
fibril_mutex_unlock(&_signal_mutex);
288
* Sets a new handler for the given signal number.
290
* @param sig Signal number to set handler for.
291
* @param func Handler function.
292
* @return SIG_ERR on failure, original handler on success.
294
void (*posix_signal(int sig, void (*func)(int)))(int)
296
struct posix_sigaction new = {
302
struct posix_sigaction old;
303
if (posix_sigaction(sig, func == NULL ? NULL : &new, &old) == 0) {
304
return old.sa_handler;
313
posix_siginfo_t siginfo;
317
* Queue blocked signal.
319
* @param signo Signal number.
320
* @param siginfo Additional information about the signal.
322
static void _queue_signal(int signo, posix_siginfo_t *siginfo)
324
assert(signo >= 0 && signo <= _TOP_SIGNAL);
325
assert(siginfo != NULL);
327
signal_queue_item *item = malloc(sizeof(signal_queue_item));
328
link_initialize(&(item->link));
330
memcpy(&item->siginfo, siginfo, sizeof(posix_siginfo_t));
331
list_append(&(item->link), &_signal_queue);
336
* Executes an action associated with the given signal.
338
* @param signo Signal number.
339
* @param siginfo Additional information about the circumstances of this raise.
340
* @return 0 if the action has been successfully executed. -1 if the signal is
343
static int _raise_sigaction(int signo, posix_siginfo_t *siginfo)
345
assert(signo >= 0 && signo <= _TOP_SIGNAL);
346
assert(siginfo != NULL);
348
fibril_mutex_lock(&_signal_mutex);
350
struct posix_sigaction action = _signal_actions[signo];
352
if (posix_sigismember(&_signal_mask, signo) ||
353
action.sa_handler == SIG_HOLD) {
354
_queue_signal(signo, siginfo);
355
fibril_mutex_unlock(&_signal_mutex);
359
/* Modifying signal mask is unnecessary,
360
* signal handling is serialized.
363
if ((action.sa_flags & SA_RESETHAND) && signo != SIGILL && signo != SIGTRAP) {
364
_signal_actions[signo] = (struct posix_sigaction) DEFAULT_HANDLER;
367
if (action.sa_flags & SA_SIGINFO) {
368
assert(action.sa_sigaction != NULL);
369
action.sa_sigaction(signo, siginfo, NULL);
371
assert(action.sa_handler != NULL);
372
action.sa_handler(signo);
375
fibril_mutex_unlock(&_signal_mutex);
381
* Raise all unblocked previously queued signals.
383
static void _dequeue_unblocked_signals()
385
link_t *iterator = _signal_queue.head.next;
388
while (iterator != &(_signal_queue).head) {
389
next = iterator->next;
391
signal_queue_item *item =
392
list_get_instance(iterator, signal_queue_item, link);
394
if (!posix_sigismember(&_signal_mask, item->signo) &&
395
_signal_actions[item->signo].sa_handler != SIG_HOLD) {
396
list_remove(&(item->link));
397
_raise_sigaction(item->signo, &(item->siginfo));
406
* Raise a signal for the calling process.
408
* @param sig Signal number.
409
* @return -1 with errno set on failure, 0 on success.
411
int posix_raise(int sig)
413
if (sig >= 0 && sig <= _TOP_SIGNAL) {
414
posix_siginfo_t siginfo = {
418
return _raise_sigaction(sig, &siginfo);
426
* Raises a signal for a selected process.
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.
433
int posix_kill(posix_pid_t pid, int signo)
441
if (signo > _TOP_SIGNAL) {
446
if (pid == (posix_pid_t) task_get_id()) {
447
return posix_raise(signo);
455
/* Nothing else supported yet. */
464
* Send a signal to a process group. Always fails at the moment because of
465
* lack of this functionality in HelenOS.
467
* @param pid PID of the process group.
468
* @param sig Signal number.
469
* @return -1 on failure, 0 on success (see kill()).
471
int posix_killpg(posix_pid_t pid, int sig)
474
return posix_kill(-pid, sig);
478
* Outputs information about the signal to the standard error stream.
480
* @param pinfo SigInfo struct to write.
481
* @param message String to output alongside human-readable signal description.
483
void posix_psiginfo(const posix_siginfo_t *pinfo, const char *message)
485
assert(pinfo != NULL);
486
posix_psignal(pinfo->si_signo, message);
487
// TODO: print si_code
491
* Outputs information about the signal to the standard error stream.
493
* @param signum Signal number.
494
* @param message String to output alongside human-readable signal description.
496
void posix_psignal(int signum, const char *message)
498
char *sigmsg = posix_strsignal(signum);
499
if (message == NULL || *message == '\0') {
500
fprintf(stderr, "%s\n", sigmsg);
502
fprintf(stderr, "%s: %s\n", message, sigmsg);
507
* Manipulate the signal mask of the calling thread.
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.
514
int posix_thread_sigmask(int how, const posix_sigset_t *restrict set,
515
posix_sigset_t *restrict oset)
517
fibril_mutex_lock(&_signal_mutex);
520
*oset = _signal_mask;
525
_signal_mask |= *set;
528
_signal_mask &= ~*set;
534
fibril_mutex_unlock(&_signal_mutex);
539
_dequeue_unblocked_signals();
541
fibril_mutex_unlock(&_signal_mutex);
547
* Manipulate the signal mask of the process.
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.
554
int posix_sigprocmask(int how, const posix_sigset_t *restrict set,
555
posix_sigset_t *restrict oset)
557
int result = posix_thread_sigmask(how, set, oset);