master
  1// Userspace emulation of `raise` and `signal`.
  2//
  3// WebAssembly doesn't support asynchronous signal delivery, so we can't
  4// support it in WASI libc. But we can make things like `raise` work.
  5
  6#define _WASI_EMULATED_SIGNAL
  7#define _ALL_SOURCE
  8#define _GNU_SOURCE
  9#include <signal.h>
 10#include <stdio.h>
 11#include <stdlib.h>
 12#include <errno.h>
 13#include <string.h>
 14#include <assert.h>
 15
 16void __SIG_IGN(int sig) {
 17    // do nothing
 18}
 19
 20_Noreturn
 21void __SIG_ERR(int sig) {
 22    __builtin_trap();
 23}
 24
 25_Noreturn
 26static void core_handler(int sig) {
 27    fprintf(stderr, "Program received fatal signal: %s\n", strsignal(sig));
 28    abort();
 29}
 30
 31_Noreturn
 32static void terminate_handler(int sig) {
 33    fprintf(stderr, "Program received termination signal: %s\n", strsignal(sig));
 34    abort();
 35}
 36
 37_Noreturn
 38static void stop_handler(int sig) {
 39    fprintf(stderr, "Program received stop signal: %s\n", strsignal(sig));
 40    abort();
 41}
 42
 43static void continue_handler(int sig) {
 44    // do nothing
 45}
 46
 47static const sighandler_t default_handlers[_NSIG] = {
 48    // Default behavior: "core".
 49    [SIGABRT] = core_handler,
 50    [SIGBUS] = core_handler,
 51    [SIGFPE] = core_handler,
 52    [SIGILL] = core_handler,
 53#if SIGIOT != SIGABRT
 54    [SIGIOT] = core_handler,
 55#endif
 56    [SIGQUIT] = core_handler,
 57    [SIGSEGV] = core_handler,
 58    [SIGSYS] = core_handler,
 59    [SIGTRAP] = core_handler,
 60    [SIGXCPU] = core_handler,
 61    [SIGXFSZ] = core_handler,
 62#if defined(SIGUNUSED) && SIGUNUSED != SIGSYS
 63    [SIGUNUSED] = core_handler,
 64#endif
 65
 66    // Default behavior: ignore.
 67    [SIGCHLD] = SIG_IGN,
 68#if defined(SIGCLD) && SIGCLD != SIGCHLD
 69    [SIGCLD] = SIG_IGN,
 70#endif
 71    [SIGURG] = SIG_IGN,
 72    [SIGWINCH] = SIG_IGN,
 73
 74    // Default behavior: "continue".
 75    [SIGCONT] = continue_handler,
 76
 77    // Default behavior: "stop".
 78    [SIGSTOP] = stop_handler,
 79    [SIGTSTP] = stop_handler,
 80    [SIGTTIN] = stop_handler,
 81    [SIGTTOU] = stop_handler,
 82
 83    // Default behavior: "terminate".
 84    [SIGHUP] = terminate_handler,
 85    [SIGINT] = terminate_handler,
 86    [SIGKILL] = terminate_handler,
 87    [SIGUSR1] = terminate_handler,
 88    [SIGUSR2] = terminate_handler,
 89    [SIGPIPE] = terminate_handler,
 90    [SIGALRM] = terminate_handler,
 91    [SIGTERM] = terminate_handler,
 92    [SIGSTKFLT] = terminate_handler,
 93    [SIGVTALRM] = terminate_handler,
 94    [SIGPROF] = terminate_handler,
 95    [SIGIO] = terminate_handler,
 96#if SIGPOLL != SIGIO
 97    [SIGPOLL] = terminate_handler,
 98#endif
 99    [SIGPWR] = terminate_handler,
100};
101
102static sighandler_t handlers[_NSIG];
103
104int raise(int sig) {
105    if (sig < 0 || sig >= _NSIG) {
106        errno = EINVAL;
107        return -1;
108    }
109
110    sighandler_t func = handlers[sig];
111
112    if (func == NULL) {
113        default_handlers[sig](sig);
114    } else {
115        func(sig);
116    }
117
118    return 0;
119}
120
121void (*signal(int sig, void (*func)(int)))(int) {
122    assert(SIG_DFL == NULL);
123
124    if (sig < 0 || sig >= _NSIG) {
125        errno = EINVAL;
126        return SIG_ERR;
127    }
128
129    if (sig == SIGKILL || sig == SIGSTOP) {
130        errno = EINVAL;
131        return SIG_ERR;
132    }
133
134    sighandler_t old = handlers[sig];
135
136    handlers[sig] = func;
137
138    return old;
139}
140
141extern __typeof(signal) bsd_signal __attribute__((weak, alias("signal")));
142extern __typeof(signal) __sysv_signal __attribute__((weak, alias("signal")));