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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c8bb1633 was fdf97f6, checked in by Vojtech Horky <vojtechhorky@…>, 12 years ago

Libposix functions are without posix_ prefix

Prior this commit, libposix headers declared all functions as posix_*
and used macros to rename e.g. strncpy to posix_strncpy in all (ported)
sources.

After this change, libposix headers look as normal POSIX compliant headers
(well, almost) and no renaming is done in the source codei (of the ported
applications). Instead, the renaming is done at object files level to
bypass weird problems that are bound to happen if you use macros.

The scheme is following. libposix headers use special macro to declare
the names. When included from outside, the functions have their normal
(standard) names. When included from the libposix sources, posix_ prefix
is added. Thus, when libposix is compiled and linked, it contains the
posix_* naming while compiling of ported software uses the normal
non-prefixed versions. This way the posix_* can use HelenOS libc without
any problem. Before linking, the posix_* prefix is removed from all
symbols and special prefix helenos_libc_ is added to all functions
that exists in our (HelenOS) libc and its name clashes with the POSIX
one.

The following happens, for example, to the open() function that exists in
both libposix and in libc.

  • Headers and sources of libc are left intact.
  • Copy of libc.a is made and to all clashing functions is added the helenos_libc prefix. This library is called libc4posix.a.
  • POSIX_DEF(open)(const char *) is used in libposix headers. This macro expands to plain open when included from the "outside world". But it expands to posix_open when included from libposix sources.
  • Libposix is compiled and linked, containing posix_open() that internally calls open() [the original one from libc].
  • Libposix is transformed - all open() are replaced with prefix variant: helenos_libc_open() and all posix_open() are replaced with open(). The transformed library is stored as libposixaslibc.a

Binutils and PCC are then linked with libc4posix and libposixaslibc
libraries instead of libc and libposix as was done previously.

WARNING: it looks that binutils, PCC and MSIM still works but not all
architectures were tested.

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