blob: 2163a7a752e3771698b1a2bd6491e898362f0163 [file] [log] [blame]
#include "caffe2/utils/signal_handler.h"
#include "caffe2/core/logging.h"
#if defined(_MSC_VER)
// Currently we do not support signal handling in Windows yet - below is a
// minimal implementation that makes things compile.
namespace caffe2 {
SignalHandler::SignalHandler(
SignalHandler::Action SIGINT_action,
SignalHandler::Action SIGHUP_action) {}
SignalHandler::~SignalHandler() {}
bool SignalHandler::GotSIGINT() {
return false;
}
bool SignalHandler::GotSIGHUP() {
return false;
}
SignalHandler::Action SignalHandler::CheckForSignals() {
return SignalHandler::Action::NONE;
}
} // namespace caffe2
#else // defined(_MSC_VER)
// Normal signal handler implementation.
#include <atomic>
#include <signal.h>
#include <unordered_set>
namespace {
static struct sigaction previous_sighup;
static struct sigaction previous_sigint;
static volatile sig_atomic_t sigint_count = 0;
static volatile sig_atomic_t sighup_count = 0;
static std::atomic<int> hooked_up_count{0};
void handle_signal(int signal) {
switch (signal) {
case SIGHUP:
sighup_count += 1;
if (previous_sighup.sa_handler) {
previous_sighup.sa_handler(signal);
}
break;
case SIGINT:
sigint_count += 1;
if (previous_sigint.sa_handler) {
previous_sigint.sa_handler(signal);
}
break;
}
}
void HookupHandler() {
if (hooked_up_count++) {
return;
}
struct sigaction sa;
// Setup the handler
sa.sa_handler = &handle_signal;
// Restart the system call, if at all possible
sa.sa_flags = SA_RESTART;
// Block every signal during the handler
sigfillset(&sa.sa_mask);
// Intercept SIGHUP and SIGINT
if (sigaction(SIGHUP, &sa, nullptr) == -1) {
LOG(FATAL) << "Cannot install SIGHUP handler.";
}
if (sigaction(SIGINT, &sa, nullptr) == -1) {
LOG(FATAL) << "Cannot install SIGINT handler.";
}
}
// Set the signal handlers to the default.
void UnhookHandler() {
if (--hooked_up_count > 0) {
return;
}
struct sigaction sa;
// Setup the sighub handler
sa.sa_handler = SIG_DFL;
// Restart the system call, if at all possible
sa.sa_flags = SA_RESTART;
// Block every signal during the handler
sigfillset(&sa.sa_mask);
// Intercept SIGHUP and SIGINT
if (sigaction(SIGHUP, &sa, &previous_sighup) == -1) {
LOG(FATAL) << "Cannot uninstall SIGHUP handler.";
}
if (sigaction(SIGINT, &sa, &previous_sigint) == -1) {
LOG(FATAL) << "Cannot uninstall SIGINT handler.";
}
}
} // namespace
namespace caffe2 {
SignalHandler::SignalHandler(SignalHandler::Action SIGINT_action,
SignalHandler::Action SIGHUP_action):
SIGINT_action_(SIGINT_action),
SIGHUP_action_(SIGHUP_action),
my_sigint_count_(sigint_count),
my_sighup_count_(sighup_count) {
HookupHandler();
}
SignalHandler::~SignalHandler() {
UnhookHandler();
}
// Return true iff a SIGINT has been received since the last time this
// function was called.
bool SignalHandler::GotSIGINT() {
uint64_t count = sigint_count;
bool result = (count != my_sigint_count_);
my_sigint_count_ = count;
return result;
}
// Return true iff a SIGHUP has been received since the last time this
// function was called.
bool SignalHandler::GotSIGHUP() {
uint64_t count = sighup_count;
bool result = (count != my_sighup_count_);
my_sighup_count_ = count;
return result;
}
SignalHandler::Action SignalHandler::CheckForSignals() {
if (GotSIGHUP()) {
return SIGHUP_action_;
}
if (GotSIGINT()) {
return SIGINT_action_;
}
return SignalHandler::Action::NONE;
}
} // namespace caffe2
#endif // defined(_MSC_VER)