94 lines
4.2 KiB

#include "SignalHandler.h"
#include <csignal>
#include <iostream>
namespace storm {
namespace utility {
namespace resources {
// Maximal waiting time after abort signal before terminating
const int maxWaitTime = 3;
SignalInformation::SignalInformation() : terminate(false), lastSignal(0) {
}
SignalInformation::~SignalInformation() {
// Intentionally left empty.
}
SignalInformation& SignalInformation::infos() {
static SignalInformation signalInfo;
return signalInfo;
}
/*!
* Signal handler for aborts, etc.
* After the first signal the handler waits a number of seconds to let the program print preliminary results
* which were computed up this point. If the waiting time is exceeded or if a second signal was raised
* in the mean time, the program immediately terminates.
*
* @param signal Exit code of signal.
*/
void signalHandler(int signal) {
if (!isTerminate()) {
// First time we get an abort signal
// We give the program a number of seconds to print results obtained so far before termination
std::cerr << "ERROR: The program received signal " << signal << " and will be aborted in " << maxWaitTime << "s." << std::endl;
SignalInformation::infos().setTerminate(true);
// Remember original signal such that the program returns the correct original signal
SignalInformation::infos().setErrorCode(signal);
// Trigger a new signal after waitTime
setTimeoutAlarm(maxWaitTime);
} else {
// Second time we get a signal
// We now definitely have to terminate as fast as possible
if (SignalInformation::infos().getErrorCode() == SIGXCPU) {
std::cerr << "TIMEOUT." << std::endl;
} else if (SignalInformation::infos().getErrorCode() == ENOMEM) {
std::cerr << "OUT OF MEMORY." << std::endl;
} else if (SignalInformation::infos().getErrorCode() == SIGABRT || SignalInformation::infos().getErrorCode() == SIGINT) {
std::cerr << "ABORT." << std::endl;
} else {
std::cerr << "Received signal " << signal << std::endl;
}
quickest_exit(SignalInformation::infos().getErrorCode());
}
}
void installSignalHandler() {
// We use the newer sigaction instead of signal
struct sigaction sa;
sa.sa_handler = signalHandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
// CPU Limit
if (sigaction(SIGXCPU, &sa, nullptr) == -1) {
std::cerr << "FATAL: Installing a signal handler failed." << std::endl;
}
// Memory out
if (sigaction(ENOMEM, &sa, nullptr) == -1) {
std::cerr << "FATAL: Installing a signal handler failed." << std::endl;
}
if (sigaction(SIGSEGV, &sa, nullptr) == -1) {
std::cerr << "FATAL: Installing a signal handler failed." << std::endl;
}
if (sigaction(SIGABRT, &sa, nullptr) == -1) {
std::cerr << "FATAL: Installing a signal handler failed." << std::endl;
}
if (sigaction(SIGINT, &sa, nullptr) == -1) {
std::cerr << "FATAL: Installing a signal handler failed." << std::endl;
}
if (sigaction(SIGTERM, &sa, nullptr) == -1) {
std::cerr << "FATAL: Installing a signal handler failed." << std::endl;
}
if (sigaction(SIGALRM, &sa, nullptr) == -1) {
std::cerr << "FATAL: Installing a signal handler failed." << std::endl;
}
}
}
}
}