1 #include "caffe2/utils/signal_handler.h" 2 #include "caffe2/core/logging.h" 4 #if defined(CAFFE2_SUPPORTS_SIGNAL_HANDLER) 11 #include <sys/syscall.h> 12 #include <sys/types.h> 21 #include <unordered_set> 23 #include "caffe2/core/init.h" 27 #define SYS_gettid __NR_gettid 30 #define SYS_tgkill __NR_tgkill 36 struct sigaction previousSighup;
37 struct sigaction previousSigint;
38 std::atomic<int> sigintCount(0);
39 std::atomic<int> sighupCount(0);
40 std::atomic<int> hookedUpCount(0);
42 void handleSignal(
int signal) {
47 if (previousSighup.sa_handler) {
48 previousSighup.sa_handler(signal);
53 if (previousSigint.sa_handler) {
54 previousSigint.sa_handler(signal);
60 void hookupHandler() {
61 if (hookedUpCount++) {
66 sa.sa_handler = &handleSignal;
68 sa.sa_flags = SA_RESTART;
70 sigfillset(&sa.sa_mask);
72 if (sigaction(SIGHUP, &sa, &previousSighup) == -1) {
73 LOG(FATAL) <<
"Cannot install SIGHUP handler.";
75 if (sigaction(SIGINT, &sa, &previousSigint) == -1) {
76 LOG(FATAL) <<
"Cannot install SIGINT handler.";
81 void unhookHandler() {
82 if (--hookedUpCount > 0) {
87 sa.sa_handler = SIG_DFL;
89 sa.sa_flags = SA_RESTART;
91 sigfillset(&sa.sa_mask);
93 if (sigaction(SIGHUP, &previousSighup,
nullptr) == -1) {
94 LOG(FATAL) <<
"Cannot uninstall SIGHUP handler.";
96 if (sigaction(SIGINT, &previousSigint,
nullptr) == -1) {
97 LOG(FATAL) <<
"Cannot uninstall SIGINT handler.";
101 #if defined(CAFFE2_SUPPORTS_FATAL_SIGNAL_HANDLERS) 103 std::mutex fatalSignalHandlersInstallationMutex;
104 bool fatalSignalHandlersInstalled;
107 struct sigaction previousSigusr2;
110 std::atomic<bool> fatalSignalReceived(
false);
113 const char* fatalSignalName(
"<UNKNOWN>");
118 pthread_cond_t writingCond = PTHREAD_COND_INITIALIZER;
119 pthread_mutex_t writingMutex = PTHREAD_MUTEX_INITIALIZER;
124 struct sigaction previous;
125 } kSignalHandlers[] = {
126 {
"SIGABRT", SIGABRT, {} },
127 {
"SIGINT", SIGINT, {} },
128 {
"SIGILL", SIGILL, {} },
129 {
"SIGFPE", SIGFPE, {} },
130 {
"SIGBUS", SIGBUS, {} },
131 {
"SIGSEGV", SIGSEGV, {} },
135 struct sigaction* getPreviousSigaction(
int signum) {
136 for (
auto handler = kSignalHandlers; handler->name !=
nullptr; handler++) {
137 if (handler->signum == signum) {
138 return &handler->previous;
144 const char* getSignalName(
int signum) {
145 for (
auto handler = kSignalHandlers; handler->name !=
nullptr; handler++) {
146 if (handler->signum == signum) {
147 return handler->name;
153 _Unwind_Reason_Code unwinder(
struct _Unwind_Context* context,
void* userInfo) {
154 auto& pcs = *
reinterpret_cast<std::vector<uintptr_t>*
>(userInfo);
155 pcs.push_back(_Unwind_GetIP(context));
156 return _URC_NO_REASON;
159 std::vector<uintptr_t> getBacktrace() {
160 std::vector<uintptr_t> pcs;
161 _Unwind_Backtrace(unwinder, &pcs);
165 void printStacktrace() {
166 std::vector<uintptr_t> pcs = getBacktrace();
169 for (uintptr_t pcAddr : pcs) {
170 const void* pc =
reinterpret_cast<const void*
>(pcAddr);
171 const char* path =
nullptr;
172 const char* name =
"???";
173 char* demangled =
nullptr;
176 std::cerr <<
"[" << i <<
"] ";
177 if (dladdr(pc, &info)) {
178 path = info.dli_fname;
179 name = info.dli_sname ?:
"???";
180 offset =
reinterpret_cast<uintptr_t
>(pc) -
181 reinterpret_cast<uintptr_t>(info.dli_saddr);
184 demangled = abi::__cxa_demangle(name,
nullptr,
nullptr, &status);
191 std::cerr <<
"+" <<
reinterpret_cast<void*
>(offset);
193 std::cerr <<
"(" << pc <<
")";
195 std::cerr <<
" in " << path;
197 std::cerr << std::endl;
205 void callPreviousSignalHandler(
206 struct sigaction* action,
210 if (!action->sa_handler) {
213 if ((action->sa_flags & SA_SIGINFO) == SA_SIGINFO) {
214 action->sa_sigaction(signum, info, ctx);
216 action->sa_handler(signum);
221 void stacktraceSignalHandler(
bool needsLock) {
223 pthread_mutex_lock(&writingMutex);
225 pid_t tid = syscall(SYS_gettid);
226 std::cerr << fatalSignalName <<
"(" << fatalSignum <<
"), Thread " << tid
227 <<
": " << std::endl;
229 std::cerr << std::endl;
231 pthread_mutex_unlock(&writingMutex);
232 pthread_cond_signal(&writingCond);
237 void fatalSignalHandler(
int signum) {
239 const char* name = getSignalName(signum);
243 if (fatalSignalReceived) {
248 fatalSignalReceived =
true;
250 fatalSignum = signum;
251 fatalSignalName = name;
254 DIR* procDir = opendir(
"/proc/self/task");
256 pid_t pid = getpid();
257 pid_t currentTid = syscall(SYS_gettid);
258 struct dirent* entry;
259 pthread_mutex_lock(&writingMutex);
260 while ((entry = readdir(procDir)) !=
nullptr) {
261 if (entry->d_name[0] ==
'.') {
264 pid_t tid = atoi(entry->d_name);
268 if (tid != currentTid) {
269 syscall(SYS_tgkill, pid, tid, SIGUSR2);
270 pthread_cond_wait(&writingCond, &writingMutex);
272 stacktraceSignalHandler(
false);
275 pthread_mutex_unlock(&writingMutex);
277 perror(
"Failed to open /proc/self/task");
279 sigaction(signum, getPreviousSigaction(signum),
nullptr);
284 void stacktraceSignalHandler(
int signum, siginfo_t* info,
void* ctx) {
285 if (fatalSignalReceived) {
286 stacktraceSignalHandler(
true);
290 callPreviousSignalHandler(&previousSigusr2, signum, info, ctx);
299 void installFatalSignalHandlers() {
300 std::lock_guard<std::mutex> locker(fatalSignalHandlersInstallationMutex);
301 if (fatalSignalHandlersInstalled) {
304 fatalSignalHandlersInstalled =
true;
306 sigemptyset(&sa.sa_mask);
309 sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
310 sa.sa_handler = ::fatalSignalHandler;
311 for (
auto* handler = kSignalHandlers; handler->name !=
nullptr; handler++) {
312 if (sigaction(handler->signum, &sa, &handler->previous)) {
313 std::string str(
"Failed to add ");
314 str += handler->name;
319 sa.sa_sigaction = ::stacktraceSignalHandler;
320 if (sigaction(SIGUSR2, &sa, &::previousSigusr2)) {
321 perror(
"Failed to add SIGUSR2 handler!");
325 void uninstallFatalSignalHandlers() {
326 std::lock_guard<std::mutex> locker(fatalSignalHandlersInstallationMutex);
327 if (!fatalSignalHandlersInstalled) {
330 fatalSignalHandlersInstalled =
false;
331 for (
auto* handler = kSignalHandlers; handler->name !=
nullptr; handler++) {
332 if (sigaction(handler->signum, &handler->previous,
nullptr)) {
333 std::string str(
"Failed to remove ");
334 str += handler->name;
338 handler->previous = {};
341 if (sigaction(SIGUSR2, &::previousSigusr2,
nullptr)) {
342 perror(
"Failed to add SIGUSR2 handler!");
344 ::previousSigusr2 = {};
347 #endif // defined(CAFFE2_SUPPORTS_FATAL_SIGNAL_HANDLERS) 351 #if defined(CAFFE2_SUPPORTS_FATAL_SIGNAL_HANDLERS) 353 caffe2_print_stacktraces,
355 "If set, prints stacktraces when a fatal signal is raised.");
360 SignalHandler::SignalHandler(
361 SignalHandler::Action SIGINT_action,
362 SignalHandler::Action SIGHUP_action)
363 : SIGINT_action_(SIGINT_action),
364 SIGHUP_action_(SIGHUP_action),
365 my_sigint_count_(sigintCount),
366 my_sighup_count_(sighupCount) {
370 SignalHandler::~SignalHandler() {
376 bool SignalHandler::GotSIGINT() {
377 uint64_t count = sigintCount;
378 bool result = (count != my_sigint_count_);
379 my_sigint_count_ = count;
385 bool SignalHandler::GotSIGHUP() {
386 uint64_t count = sighupCount;
387 bool result = (count != my_sighup_count_);
388 my_sighup_count_ = count;
392 SignalHandler::Action SignalHandler::CheckForSignals() {
394 return SIGHUP_action_;
397 return SIGINT_action_;
399 return SignalHandler::Action::NONE;
402 #if defined(CAFFE2_SUPPORTS_FATAL_SIGNAL_HANDLERS) 403 void setPrintStackTracesOnFatalSignal(
bool print) {
405 installFatalSignalHandlers();
407 uninstallFatalSignalHandlers();
410 bool printStackTracesOnFatalSignal() {
411 std::lock_guard<std::mutex> locker(fatalSignalHandlersInstallationMutex);
412 return fatalSignalHandlersInstalled;
416 bool Caffe2InitFatalSignalHandler(
int*,
char***) {
417 if (caffe2::FLAGS_caffe2_print_stacktraces) {
418 setPrintStackTracesOnFatalSignal(
true);
423 REGISTER_CAFFE2_INIT_FUNCTION(
424 Caffe2InitFatalSignalHandler,
425 &Caffe2InitFatalSignalHandler,
426 "Inits signal handlers for fatal signals so we can see what if" 427 " caffe2_print_stacktraces is set.");
430 #endif // defined(CAFFE2_SUPPORTS_FATAL_SIGNAL_HANDLERS) 433 #else // defined(CAFFE2_SUPPORTS_SIGNAL_HANDLER) 438 SignalHandler::SignalHandler(
439 SignalHandler::Action SIGINT_action,
440 SignalHandler::Action SIGHUP_action) {}
441 SignalHandler::~SignalHandler() {}
442 bool SignalHandler::GotSIGINT() {
445 bool SignalHandler::GotSIGHUP() {
448 SignalHandler::Action SignalHandler::CheckForSignals() {
449 return SignalHandler::Action::NONE;
453 #endif // defined(CAFFE2_SUPPORTS_SIGNAL_HANDLER) A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...