2021-05-25 18:45:46 +03:00
|
|
|
#include "idris_signal.h"
|
|
|
|
|
2021-07-05 08:14:58 +03:00
|
|
|
#include <assert.h>
|
2021-07-04 10:53:53 +03:00
|
|
|
#include <errno.h>
|
2021-07-05 08:14:58 +03:00
|
|
|
#include <limits.h>
|
2021-05-25 18:45:46 +03:00
|
|
|
#include <signal.h>
|
2021-07-05 08:14:58 +03:00
|
|
|
#include <stdatomic.h>
|
|
|
|
#include <stdio.h>
|
2021-07-04 10:53:53 +03:00
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "idris_util.h"
|
2021-05-25 18:45:46 +03:00
|
|
|
|
2021-07-05 08:14:58 +03:00
|
|
|
static_assert(ATOMIC_LONG_LOCK_FREE == 2,
|
|
|
|
"when not lock free, atomic functions are not async-signal-safe");
|
2021-05-25 18:45:46 +03:00
|
|
|
|
2021-07-05 08:14:58 +03:00
|
|
|
#define N_SIGNALS 32
|
|
|
|
static atomic_long signal_count[N_SIGNALS];
|
2021-05-25 18:45:46 +03:00
|
|
|
|
2021-07-05 08:14:58 +03:00
|
|
|
void _collect_signal(int signum) {
|
2021-07-04 10:53:53 +03:00
|
|
|
IDRIS2_VERIFY(signum >= 0 && signum < N_SIGNALS, "signal number out of range: %d", signum);
|
2021-05-25 18:45:46 +03:00
|
|
|
|
2021-07-05 08:14:58 +03:00
|
|
|
long prev = atomic_fetch_add(&signal_count[signum], 1);
|
2021-07-04 10:53:53 +03:00
|
|
|
IDRIS2_VERIFY(prev != LONG_MAX, "signal count overflow");
|
2021-05-25 18:45:46 +03:00
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
//re-instate signal handler
|
2021-07-04 10:53:53 +03:00
|
|
|
IDRIS2_VERIFY(signal(signum, _collect_signal) != SIG_ERR, "signal failed: %s", strerror(errno));
|
2021-05-25 18:45:46 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef _WIN32
|
2021-06-25 17:51:18 +03:00
|
|
|
static inline struct sigaction _simple_handler(void (*handler)(int)) {
|
2021-05-25 18:45:46 +03:00
|
|
|
struct sigaction new_action;
|
|
|
|
|
|
|
|
new_action.sa_handler = handler;
|
|
|
|
sigemptyset (&new_action.sa_mask);
|
|
|
|
new_action.sa_flags = 0;
|
|
|
|
|
|
|
|
return new_action;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int ignore_signal(int signum) {
|
|
|
|
#ifdef _WIN32
|
|
|
|
return signal(signum, SIG_IGN) == SIG_ERR ? -1 : 0;
|
|
|
|
#else
|
|
|
|
struct sigaction handler = _simple_handler(SIG_IGN);
|
|
|
|
return sigaction(signum, &handler, NULL);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
int default_signal(int signum) {
|
|
|
|
#ifdef _WIN32
|
|
|
|
return signal(signum, SIG_DFL) == SIG_ERR ? -1 : 0;
|
|
|
|
#else
|
|
|
|
struct sigaction handler = _simple_handler(SIG_DFL);
|
|
|
|
return sigaction(signum, &handler, NULL);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
int collect_signal(int signum) {
|
|
|
|
#ifdef _WIN32
|
|
|
|
return signal(signum, _collect_signal) == SIG_ERR ? -1 : 0;
|
|
|
|
#else
|
|
|
|
struct sigaction handler = _simple_handler(_collect_signal);
|
|
|
|
return sigaction(signum, &handler, NULL);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
int handle_next_collected_signal() {
|
2021-07-05 08:14:58 +03:00
|
|
|
for (int signum = 0; signum != N_SIGNALS; ++signum) {
|
|
|
|
for (;;) {
|
|
|
|
long count = atomic_load(&signal_count[signum]);
|
|
|
|
if (count == 0) {
|
|
|
|
break;
|
|
|
|
}
|
2021-07-04 10:53:53 +03:00
|
|
|
IDRIS2_VERIFY(count >= 0, "signal count overflow");
|
2021-07-05 08:14:58 +03:00
|
|
|
if (atomic_compare_exchange_strong(&signal_count[signum], &count, count - 1)) {
|
|
|
|
return signum;
|
|
|
|
}
|
2021-05-25 18:45:46 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int raise_signal(int signum) {
|
|
|
|
return raise(signum);
|
|
|
|
}
|
|
|
|
|
|
|
|
int send_signal(int pid, int signum) {
|
|
|
|
#ifdef _WIN32
|
2021-07-05 08:14:58 +03:00
|
|
|
// TODO: ignores pid
|
2021-05-25 18:45:46 +03:00
|
|
|
return raise_signal(signum);
|
|
|
|
#else
|
|
|
|
return kill(pid, signum);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
int sighup() {
|
|
|
|
#ifdef _WIN32
|
|
|
|
return -1;
|
|
|
|
#else
|
|
|
|
return SIGHUP;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
int sigint() {
|
|
|
|
return SIGINT;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sigabrt() {
|
|
|
|
return SIGABRT;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sigquit() {
|
|
|
|
#ifdef _WIN32
|
|
|
|
return -1;
|
|
|
|
#else
|
|
|
|
return SIGQUIT;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
int sigill() {
|
|
|
|
return SIGILL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sigsegv() {
|
|
|
|
return SIGSEGV;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sigtrap() {
|
|
|
|
#ifdef _WIN32
|
|
|
|
return -1;
|
|
|
|
#else
|
|
|
|
return SIGTRAP;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
int sigfpe() {
|
|
|
|
return SIGFPE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sigusr1() {
|
|
|
|
#ifdef _WIN32
|
|
|
|
return -1;
|
|
|
|
#else
|
|
|
|
return SIGUSR1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
int sigusr2() {
|
|
|
|
#ifdef _WIN32
|
|
|
|
return -1;
|
|
|
|
#else
|
|
|
|
return SIGUSR2;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|