#include <csignal>
#include <unistd.h>
#include <nix/util/signals.hh>
#include "signals.hxx"
extern "C" {
// Storage for previous signal handlers
static struct sigaction old_sigint_action;
static struct sigaction old_sigterm_action;
static struct sigaction old_sighup_action;
// Get pointer to the old action structure for a given signal
static struct sigaction* get_old_action(int sig) {
switch (sig) {
case SIGINT: return &old_sigint_action;
case SIGTERM: return &old_sigterm_action;
case SIGHUP: return &old_sighup_action;
default: return nullptr;
}
}
// C signal handler that runs immediately in signal context
// This calls nix::triggerInterrupt() synchronously then defers to the previous handler
static void hercules_nix_signal_handler(int sig) {
// Set the Nix interrupt flag immediately
// This ensures checkInterrupt() calls after EINTR will work correctly
nix::unix::triggerInterrupt();
// Call the previous handler to preserve existing behavior
struct sigaction* old_action = get_old_action(sig);
if (old_action && old_action->sa_handler != SIG_DFL && old_action->sa_handler != SIG_IGN) {
if (old_action->sa_flags & SA_SIGINFO) {
// Previous handler expects siginfo_t
// We can't call it properly without the siginfo, so just call the basic handler
if (old_action->sa_handler) {
old_action->sa_handler(sig);
}
} else {
// Previous handler is a simple function pointer
old_action->sa_handler(sig);
}
}
}
// Install our C signal handler for the given signal, chaining to the previous handler
// Returns 0 on success, -1 on error
int hercules_install_signal_handler(int sig) {
struct sigaction new_action;
new_action.sa_handler = hercules_nix_signal_handler;
sigemptyset(&new_action.sa_mask);
new_action.sa_flags = 0; // Ensure SA_RESTART is not set
struct sigaction* old_action = get_old_action(sig);
if (!old_action) {
return -1; // Unknown signal
}
// Install new handler and save the old one
return sigaction(sig, &new_action, old_action);
}
} // extern "C"