diff options
Diffstat (limited to '')
-rw-r--r-- | libc-bottom-half/signal/signal.c | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/libc-bottom-half/signal/signal.c b/libc-bottom-half/signal/signal.c new file mode 100644 index 0000000..290d6b2 --- /dev/null +++ b/libc-bottom-half/signal/signal.c @@ -0,0 +1,142 @@ +// Userspace emulation of `raise` and `signal`. +// +// WebAssembly doesn't support asynchronous signal delivery, so we can't +// support it in WASI libc. But we can make things like `raise` work. + +#define _WASI_EMULATED_SIGNAL +#define _ALL_SOURCE +#define _GNU_SOURCE +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <assert.h> + +void __SIG_IGN(int sig) { + // do nothing +} + +_Noreturn +void __SIG_ERR(int sig) { + __builtin_trap(); +} + +_Noreturn +static void core_handler(int sig) { + fprintf(stderr, "Program received fatal signal: %s\n", strsignal(sig)); + abort(); +} + +_Noreturn +static void terminate_handler(int sig) { + fprintf(stderr, "Program recieved termination signal: %s\n", strsignal(sig)); + abort(); +} + +_Noreturn +static void stop_handler(int sig) { + fprintf(stderr, "Program recieved stop signal: %s\n", strsignal(sig)); + abort(); +} + +static void continue_handler(int sig) { + // do nothing +} + +static const sighandler_t default_handlers[_NSIG] = { + // Default behavior: "core". + [SIGABRT] = core_handler, + [SIGBUS] = core_handler, + [SIGFPE] = core_handler, + [SIGILL] = core_handler, +#if SIGIOT != SIGABRT + [SIGIOT] = core_handler, +#endif + [SIGQUIT] = core_handler, + [SIGSEGV] = core_handler, + [SIGSYS] = core_handler, + [SIGTRAP] = core_handler, + [SIGXCPU] = core_handler, + [SIGXFSZ] = core_handler, +#if defined(SIGUNUSED) && SIGUNUSED != SIGSYS + [SIGUNUSED] = core_handler, +#endif + + // Default behavior: ignore. + [SIGCHLD] = SIG_IGN, +#if defined(SIGCLD) && SIGCLD != SIGCHLD + [SIGCLD] = SIG_IGN, +#endif + [SIGURG] = SIG_IGN, + [SIGWINCH] = SIG_IGN, + + // Default behavior: "continue". + [SIGCONT] = continue_handler, + + // Default behavior: "stop". + [SIGSTOP] = stop_handler, + [SIGTSTP] = stop_handler, + [SIGTTIN] = stop_handler, + [SIGTTOU] = stop_handler, + + // Default behavior: "terminate". + [SIGHUP] = terminate_handler, + [SIGINT] = terminate_handler, + [SIGKILL] = terminate_handler, + [SIGUSR1] = terminate_handler, + [SIGUSR2] = terminate_handler, + [SIGPIPE] = terminate_handler, + [SIGALRM] = terminate_handler, + [SIGTERM] = terminate_handler, + [SIGSTKFLT] = terminate_handler, + [SIGVTALRM] = terminate_handler, + [SIGPROF] = terminate_handler, + [SIGIO] = terminate_handler, +#if SIGPOLL != SIGIO + [SIGPOLL] = terminate_handler, +#endif + [SIGPWR] = terminate_handler, +}; + +static sighandler_t handlers[_NSIG]; + +int raise(int sig) { + if (sig < 0 || sig >= _NSIG) { + errno = EINVAL; + return -1; + } + + sighandler_t func = handlers[sig]; + + if (func == NULL) { + default_handlers[sig](sig); + } else { + func(sig); + } + + return 0; +} + +void (*signal(int sig, void (*func)(int)))(int) { + assert(SIG_DFL == NULL); + + if (sig < 0 || sig >= _NSIG) { + errno = EINVAL; + return SIG_ERR; + } + + if (sig == SIGKILL || sig == SIGSTOP) { + errno = EINVAL; + return SIG_ERR; + } + + sighandler_t old = handlers[sig]; + + handlers[sig] = func; + + return old; +} + +extern __typeof(signal) bsd_signal __attribute__((weak, alias("signal"))); +extern __typeof(signal) __sysv_signal __attribute__((weak, alias("signal"))); |