| #ifndef SUPPORT_ASSERT_CHECKPOINT_H |
| #define SUPPORT_ASSERT_CHECKPOINT_H |
| |
| #include <csignal> |
| #include <iostream> |
| #include <cstdlib> |
| |
| struct Checkpoint { |
| const char* file; |
| const char* func; |
| int line; |
| const char* msg; |
| |
| Checkpoint() : file(nullptr), func(nullptr), line(-1), msg(nullptr) {} |
| Checkpoint(const char* xfile, const char* xfunc, int xline, const char* xmsg) |
| : file(xfile), func(xfunc), line(xline), msg(xmsg) |
| {} |
| |
| template <class Stream> |
| void print(Stream& s) const { |
| if (!file) { |
| s << "NO CHECKPOINT\n"; |
| return; |
| } |
| s << file << ":" << line << " " << func << ": Checkpoint"; |
| if (msg) |
| s << " '" << msg << "'"; |
| s << std::endl; |
| } |
| }; |
| |
| inline Checkpoint& globalCheckpoint() { |
| static Checkpoint C; |
| return C; |
| } |
| |
| inline void clearCheckpoint() { |
| globalCheckpoint() = Checkpoint(); |
| } |
| |
| #if defined(__GNUC__) |
| #define CHECKPOINT_FUNCTION_NAME __PRETTY_FUNCTION__ |
| #else |
| #define CHECKPOINT_FUNCTION_NAME __func__ |
| #endif |
| |
| #define CHECKPOINT(msg) globalCheckpoint() = Checkpoint(__FILE__, CHECKPOINT_FUNCTION_NAME, __LINE__, msg); |
| |
| inline void checkpointSignalHandler(int signal) { |
| if (signal == SIGABRT) { |
| globalCheckpoint().print(std::cerr); |
| } else { |
| std::cerr << "Unexpected signal " << signal << " received\n"; |
| } |
| std::_Exit(EXIT_FAILURE); |
| } |
| |
| inline bool initCheckpointHandler() { |
| typedef void(*HandlerT)(int); |
| static bool isInit = false; |
| if (isInit) return true; |
| HandlerT prev_h = std::signal(SIGABRT, checkpointSignalHandler); |
| if (prev_h == SIG_ERR) { |
| std::cerr << "Setup failed.\n"; |
| std::_Exit(EXIT_FAILURE); |
| } |
| isInit = true; |
| return false; |
| } |
| |
| static bool initDummy = initCheckpointHandler(); |
| |
| #endif |