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

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

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 13.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#include "posix/signal.h"
36#include "internal/common.h"
37#include "posix/limits.h"
38#include "posix/stdlib.h"
39#include "posix/string.h"
40
41#include <errno.h>
42
43#include "libc/fibril_synch.h"
44#include "libc/task.h"
45
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 */
54
55/* Used to serialize signal handling. */
56static FIBRIL_MUTEX_INITIALIZE(_signal_mutex);
57
58static LIST_INITIALIZE(_signal_queue);
59
60static sigset_t _signal_mask = 0;
61
62#define DEFAULT_HANDLER { .sa_handler = SIG_DFL, \
63 .sa_mask = 0, .sa_flags = 0, .sa_sigaction = NULL }
64
65/* Actions associated with each signal number. */
66static struct sigaction _signal_actions[_TOP_SIGNAL + 1] = {
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,
73 DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER
74};
75
76/**
77 * Default signal handler. Executes the default action for each signal,
78 * as reasonable within HelenOS.
79 *
80 * @param signo Signal number.
81 */
82void __posix_default_signal_handler(int signo)
83{
84 switch (signo) {
85 case SIGABRT:
86 abort();
87 case SIGQUIT:
88 fprintf(stderr, "Quit signal raised. Exiting.\n");
89 exit(EXIT_FAILURE);
90 case SIGINT:
91 fprintf(stderr, "Interrupt signal caught. Exiting.\n");
92 exit(EXIT_FAILURE);
93 case SIGTERM:
94 fprintf(stderr, "Termination signal caught. Exiting.\n");
95 exit(EXIT_FAILURE);
96 case SIGSTOP:
97 fprintf(stderr, "Stop signal caught, but unsupported. Ignoring.\n");
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:
110 psignal(signo, "Hardware exception raised by user code");
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:
123 psignal(signo, "Unsupported signal caught");
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
137/**
138 * Just an empty function to get an unique pointer value for comparison.
139 *
140 * @param signo Signal number.
141 */
142void __posix_hold_signal_handler(int signo)
143{
144 /* Nothing */
145}
146
147/**
148 * Empty function to be used as ignoring handler.
149 *
150 * @param signo Signal number.
151 */
152void __posix_ignore_signal_handler(int signo)
153{
154 /* Nothing */
155}
156
157/**
158 * Clear the signal set.
159 *
160 * @param set Pointer to the signal set.
161 * @return Always returns zero.
162 */
163int sigemptyset(sigset_t *set)
164{
165 assert(set != NULL);
166
167 *set = 0;
168 return 0;
169}
170
171/**
172 * Fill the signal set (i.e. add all signals).
173 *
174 * @param set Pointer to the signal set.
175 * @return Always returns zero.
176 */
177int sigfillset(sigset_t *set)
178{
179 assert(set != NULL);
180
181 *set = UINT32_MAX;
182 return 0;
183}
184
185/**
186 * Add a signal to the set.
187 *
188 * @param set Pointer to the signal set.
189 * @param signo Signal number to add.
190 * @return Always returns zero.
191 */
192int sigaddset(sigset_t *set, int signo)
193{
194 assert(set != NULL);
195
196 *set |= (1 << signo);
197 return 0;
198}
199
200/**
201 * Delete a signal from the set.
202 *
203 * @param set Pointer to the signal set.
204 * @param signo Signal number to remove.
205 * @return Always returns zero.
206 */
207int sigdelset(sigset_t *set, int signo)
208{
209 assert(set != NULL);
210
211 *set &= ~(1 << signo);
212 return 0;
213}
214
215/**
216 * Inclusion test for a signal set.
217 *
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.
221 */
222int sigismember(const sigset_t *set, int signo)
223{
224 assert(set != NULL);
225
226 return (*set & (1 << signo)) != 0;
227}
228
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.
233 *
234 * @param sig
235 * @param act
236 * @param oact
237 */
238static void _sigaction_unsafe(int sig, const struct sigaction *restrict act,
239 struct sigaction *restrict oact)
240{
241 if (oact != NULL) {
242 memcpy(oact, &_signal_actions[sig],
243 sizeof(struct sigaction));
244 }
245
246 if (act != NULL) {
247 memcpy(&_signal_actions[sig], act,
248 sizeof(struct sigaction));
249 }
250}
251
252/**
253 * Sets a new action for the given signal number.
254 *
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
259 * is stored in the structure pointer to.
260 * @return -1 with errno set on failure, 0 on success.
261 */
262int sigaction(int sig, const struct sigaction *restrict act,
263 struct sigaction *restrict oact)
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) {
272 psignal(sig,
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"
276 " the application developer intended");
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}
285
286/**
287 * Sets a new handler for the given signal number.
288 *
289 * @param sig Signal number to set handler for.
290 * @param func Handler function.
291 * @return SIG_ERR on failure, original handler on success.
292 */
293void (*signal(int sig, void (*func)(int)))(int)
294{
295 struct sigaction new = {
296 .sa_handler = func,
297 .sa_mask = 0,
298 .sa_flags = 0,
299 .sa_sigaction = NULL
300 };
301 struct sigaction old;
302 if (sigaction(sig, func == NULL ? NULL : &new, &old) == 0) {
303 return old.sa_handler;
304 } else {
305 return SIG_ERR;
306 }
307}
308
309typedef struct {
310 link_t link;
311 int signo;
312 siginfo_t siginfo;
313} signal_queue_item;
314
315/**
316 * Queue blocked signal.
317 *
318 * @param signo Signal number.
319 * @param siginfo Additional information about the signal.
320 */
321static void _queue_signal(int signo, siginfo_t *siginfo)
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;
329 memcpy(&item->siginfo, siginfo, sizeof(siginfo_t));
330 list_append(&(item->link), &_signal_queue);
331}
332
333
334/**
335 * Executes an action associated with the given signal.
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.
341 */
342static int _raise_sigaction(int signo, siginfo_t *siginfo)
343{
344 assert(signo >= 0 && signo <= _TOP_SIGNAL);
345 assert(siginfo != NULL);
346
347 fibril_mutex_lock(&_signal_mutex);
348
349 struct sigaction action = _signal_actions[signo];
350
351 if (sigismember(&_signal_mask, signo) ||
352 action.sa_handler == SIG_HOLD) {
353 _queue_signal(signo, siginfo);
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) {
363 _signal_actions[signo] = (struct sigaction) DEFAULT_HANDLER;
364 }
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;
377}
378
379/**
380 * Raise all unblocked previously queued signals.
381 */
382static void _dequeue_unblocked_signals(void)
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
393 if (!sigismember(&_signal_mask, item->signo) &&
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
404/**
405 * Raise a signal for the calling process.
406 *
407 * @param sig Signal number.
408 * @return -1 with errno set on failure, 0 on success.
409 */
410int raise(int sig)
411{
412 if (sig >= 0 && sig <= _TOP_SIGNAL) {
413 siginfo_t siginfo = {
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 }
422}
423
424/**
425 * Raises a signal for a selected process.
426 *
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.
431 */
432int kill(pid_t pid, int signo)
433{
434 if (pid < 1) {
435 // TODO
436 errno = ENOTSUP;
437 return -1;
438 }
439
440 if (signo > _TOP_SIGNAL) {
441 errno = EINVAL;
442 return -1;
443 }
444
445 if (pid == (pid_t) task_get_id()) {
446 return raise(signo);
447 }
448
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;
460}
461
462/**
463 * Send a signal to a process group. Always fails at the moment because of
464 * lack of this functionality in HelenOS.
465 *
466 * @param pid PID of the process group.
467 * @param sig Signal number.
468 * @return -1 on failure, 0 on success (see kill()).
469 */
470int killpg(pid_t pid, int sig)
471{
472 assert(pid > 1);
473 return kill(-pid, sig);
474}
475
476/**
477 * Outputs information about the signal to the standard error stream.
478 *
479 * @param pinfo SigInfo struct to write.
480 * @param message String to output alongside human-readable signal description.
481 */
482void psiginfo(const siginfo_t *pinfo, const char *message)
483{
484 assert(pinfo != NULL);
485 psignal(pinfo->si_signo, message);
486 // TODO: print si_code
487}
488
489/**
490 * Outputs information about the signal to the standard error stream.
491 *
492 * @param signum Signal number.
493 * @param message String to output alongside human-readable signal description.
494 */
495void psignal(int signum, const char *message)
496{
497 char *sigmsg = strsignal(signum);
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
505/**
506 * Manipulate the signal mask of the calling thread.
507 *
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.
512 */
513int thread_sigmask(int how, const sigset_t *restrict set,
514 sigset_t *restrict oset)
515{
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 }
537
538 _dequeue_unblocked_signals();
539
540 fibril_mutex_unlock(&_signal_mutex);
541
542 return 0;
543}
544
545/**
546 * Manipulate the signal mask of the process.
547 *
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.
552 */
553int sigprocmask(int how, const sigset_t *restrict set,
554 sigset_t *restrict oset)
555{
556 int result = thread_sigmask(how, set, oset);
557 if (result != 0) {
558 errno = result;
559 return -1;
560 }
561 return 0;
562}
563
564/** @}
565 */
Note: See TracBrowser for help on using the repository browser.