souffle  2.0.2-371-g6315b36
SignalHandler.h
Go to the documentation of this file.
1 /*
2  * Souffle - A Datalog Compiler
3  * Copyright (c) 2017, The Souffle Developers. All rights reserved
4  * Licensed under the Universal Permissive License v 1.0 as shown at:
5  * - https://opensource.org/licenses/UPL
6  * - <souffle root>/licenses/SOUFFLE-UPL.txt
7  */
8 
9 /************************************************************************
10  *
11  * @file SignalHandler.h
12  *
13  * A signal handler for Souffle's interpreter and compiler.
14  *
15  ***********************************************************************/
16 
17 #pragma once
18 
19 #include <atomic>
20 #include <csignal>
21 #include <cstdio>
22 #include <cstdlib>
23 #include <cstring>
24 #include <iostream>
25 #include <mutex>
26 #include <string>
27 
28 namespace souffle {
29 
30 /**
31  * Class SignalHandler captures signals
32  * and reports the context where the signal occurs.
33  * The signal handler is implemented as a singleton.
34  */
35 class SignalHandler {
36 public:
37  // get singleton
38  static SignalHandler* instance() {
39  static SignalHandler singleton;
40  return &singleton;
41  }
42 
43  // Enable logging
44  void enableLogging() {
45  logMessages = true;
46  }
47  // set signal message
48  void setMsg(const char* m) {
49  if (logMessages && m != nullptr) {
50  static std::mutex outputMutex;
51  static bool sameLine = false;
52  std::lock_guard<std::mutex> guard(outputMutex);
53  if (msg != nullptr && strcmp(m, msg) == 0) {
54  std::cout << ".";
55  sameLine = true;
56  } else {
57  if (sameLine) {
58  sameLine = false;
59  std::cout << std::endl;
60  }
61  std::string outputMessage(m);
62  for (char& c : outputMessage) {
63  if (c == '\n' || c == '\t') {
64  c = ' ';
65  }
66  }
67  std::cout << "Starting work on " << outputMessage << std::endl;
68  }
69  }
70  msg = m;
71  }
72 
73  /***
74  * set signal handlers
75  */
76  void set() {
77  if (!isSet && std::getenv("SOUFFLE_ALLOW_SIGNALS") == nullptr) {
78  // register signals
79  // floating point exception
80  if ((prevFpeHandler = signal(SIGFPE, handler)) == SIG_ERR) {
81  perror("Failed to set SIGFPE signal handler.");
82  exit(1);
83  }
84  // user interrupts
85  if ((prevIntHandler = signal(SIGINT, handler)) == SIG_ERR) {
86  perror("Failed to set SIGINT signal handler.");
87  exit(1);
88  }
89  // memory issues
90  if ((prevSegVHandler = signal(SIGSEGV, handler)) == SIG_ERR) {
91  perror("Failed to set SIGSEGV signal handler.");
92  exit(1);
93  }
94  isSet = true;
95  }
96  }
97 
98  /***
99  * reset signal handlers
100  */
101  void reset() {
102  if (isSet) {
103  // reset floating point exception
104  if (signal(SIGFPE, prevFpeHandler) == SIG_ERR) {
105  perror("Failed to reset SIGFPE signal handler.");
106  exit(1);
107  }
108  // user interrupts
109  if (signal(SIGINT, prevIntHandler) == SIG_ERR) {
110  perror("Failed to reset SIGINT signal handler.");
111  exit(1);
112  }
113  // memory issues
114  if (signal(SIGSEGV, prevSegVHandler) == SIG_ERR) {
115  perror("Failed to reset SIGSEGV signal handler.");
116  exit(1);
117  }
118  isSet = false;
119  }
120  }
121 
122  /***
123  * error handling routine that prints the rule context.
124  */
125 
126  void error(const std::string& error) {
127  if (msg != nullptr) {
128  std::cerr << error << " in rule:\n" << msg << std::endl;
129  } else {
130  std::cerr << error << std::endl;
131  }
132  exit(1);
133  }
134 
135 private:
136  // signal context information
137  std::atomic<const char*> msg;
138 
139  // state of signal handler
140  bool isSet = false;
141 
142  bool logMessages = false;
143 
144  // previous signal handler routines
145  void (*prevFpeHandler)(int) = nullptr;
146  void (*prevIntHandler)(int) = nullptr;
147  void (*prevSegVHandler)(int) = nullptr;
148 
149  /**
150  * Signal handler for various types of signals.
151  */
152  static void handler(int signal) {
153  const char* msg = instance()->msg;
154  std::string error;
155  switch (signal) {
156  case SIGINT: error = "Interrupt"; break;
157  case SIGFPE: error = "Floating-point arithmetic exception"; break;
158  case SIGSEGV: error = "Segmentation violation"; break;
159  default: error = "Unknown"; break;
160  }
161  if (msg != nullptr) {
162  std::cerr << error << " signal in rule:\n" << msg << std::endl;
163  } else {
164  std::cerr << error << " signal." << std::endl;
165  }
166  exit(1);
167  }
168 
169  SignalHandler() : msg(nullptr) {}
170 };
171 
172 } // namespace souffle
souffle::SignalHandler::error
void error(const std::string &error)
Definition: SignalHandler.h:138
souffle::SignalHandler::setMsg
void setMsg(const char *m)
Definition: SignalHandler.h:60
souffle::SignalHandler::prevIntHandler
void(* prevIntHandler)(int)
Definition: SignalHandler.h:158
m
var m
Definition: htmlJsChartistMin.h:15
souffle::SignalHandler::msg
std::atomic< const char * > msg
Definition: SignalHandler.h:149
souffle::SignalHandler::set
void set()
Definition: SignalHandler.h:88
souffle::SignalHandler::isSet
bool isSet
Definition: SignalHandler.h:152
souffle::SignalHandler::SignalHandler
SignalHandler()
Definition: SignalHandler.h:181
souffle::SignalHandler::handler
static void handler(int signal)
Signal handler for various types of signals.
Definition: SignalHandler.h:164
souffle::SignalHandler::enableLogging
void enableLogging()
Definition: SignalHandler.h:56
souffle::SignalHandler::prevFpeHandler
void(* prevFpeHandler)(int)
Definition: SignalHandler.h:157
souffle::SignalHandler::instance
static SignalHandler * instance()
Definition: SignalHandler.h:50
souffle
Definition: AggregateOp.h:25
souffle::SignalHandler::logMessages
bool logMessages
Definition: SignalHandler.h:154
souffle::SignalHandler::reset
void reset()
Definition: SignalHandler.h:113
souffle::SignalHandler::prevSegVHandler
void(* prevSegVHandler)(int)
Definition: SignalHandler.h:159