#include "private.h"
volatile sig_atomic_t user_abort = false;
#if !(defined(_WIN32) && !defined(__CYGWIN__))
static volatile sig_atomic_t exit_signal = 0;
static sigset_t hooked_signals;
static bool signals_are_initialized = false;
static size_t signals_block_count = 0;
static void
signal_handler(int sig)
{
exit_signal = sig;
user_abort = true;
#ifndef TUKLIB_DOSLIKE
io_write_to_user_abort_pipe();
#endif
return;
}
#ifdef __APPLE__
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
extern void
signals_init(void)
{
static const int sigs[] = {
SIGINT,
SIGTERM,
#ifdef SIGHUP
SIGHUP,
#endif
#ifdef SIGPIPE
SIGPIPE,
#endif
#ifdef SIGXCPU
SIGXCPU,
#endif
#ifdef SIGXFSZ
SIGXFSZ,
#endif
};
sigemptyset(&hooked_signals);
for (size_t i = 0; i < ARRAY_SIZE(sigs); ++i)
sigaddset(&hooked_signals, sigs[i]);
#ifdef SIGALRM
for (size_t i = 0; message_progress_sigs[i] != 0; ++i)
sigaddset(&hooked_signals, message_progress_sigs[i]);
#endif
#ifdef USE_SIGTSTP_HANDLER
sigaddset(&hooked_signals, SIGTSTP);
#endif
struct sigaction my_sa;
my_sa.sa_mask = hooked_signals;
my_sa.sa_flags = 0;
my_sa.sa_handler = &signal_handler;
struct sigaction old;
for (size_t i = 0; i < ARRAY_SIZE(sigs); ++i) {
if (sigaction(sigs[i], NULL, &old) == 0
&& old.sa_handler == SIG_IGN)
continue;
if (sigaction(sigs[i], &my_sa, NULL))
message_signal_handler();
}
#ifdef USE_SIGTSTP_HANDLER
if (!(sigaction(SIGTSTP, NULL, &old) == 0
&& old.sa_handler == SIG_IGN)) {
my_sa.sa_handler = &mytime_sigtstp_handler;
if (sigaction(SIGTSTP, &my_sa, NULL))
message_signal_handler();
}
#endif
signals_are_initialized = true;
return;
}
#ifdef __APPLE__
# pragma GCC diagnostic pop
#endif
#ifndef __VMS
extern void
signals_block(void)
{
if (signals_are_initialized) {
if (signals_block_count++ == 0) {
const int saved_errno = errno;
mythread_sigmask(SIG_BLOCK, &hooked_signals, NULL);
errno = saved_errno;
}
}
return;
}
extern void
signals_unblock(void)
{
if (signals_are_initialized) {
assert(signals_block_count > 0);
if (--signals_block_count == 0) {
const int saved_errno = errno;
mythread_sigmask(SIG_UNBLOCK, &hooked_signals, NULL);
errno = saved_errno;
}
}
return;
}
#endif
extern void
signals_exit(void)
{
const int sig = (int)exit_signal;
if (sig != 0) {
#if defined(TUKLIB_DOSLIKE) || defined(__VMS)
set_exit_status(E_ERROR);
#else
struct sigaction sa;
sa.sa_handler = SIG_DFL;
sigfillset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(sig, &sa, NULL);
raise(sig);
#endif
}
return;
}
#else
static BOOL WINAPI
signal_handler(DWORD type lzma_attribute((__unused__)))
{
set_exit_status(E_ERROR);
user_abort = true;
return TRUE;
}
extern void
signals_init(void)
{
if (!SetConsoleCtrlHandler(&signal_handler, TRUE))
message_signal_handler();
return;
}
#endif