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" 24 #include "caffe2/core/workspace.h" 28 #define SYS_gettid __NR_gettid 31 #define SYS_tgkill __NR_tgkill 37 struct sigaction previousSighup;
38 struct sigaction previousSigint;
39 std::atomic<int> sigintCount(0);
40 std::atomic<int> sighupCount(0);
41 std::atomic<int> hookedUpCount(0);
43 void handleSignal(
int signal) {
48 if (previousSighup.sa_handler) {
49 previousSighup.sa_handler(signal);
54 if (previousSigint.sa_handler) {
55 previousSigint.sa_handler(signal);
61 void hookupHandler() {
62 if (hookedUpCount++) {
67 sa.sa_handler = &handleSignal;
69 sa.sa_flags = SA_RESTART;
71 sigfillset(&sa.sa_mask);
73 if (sigaction(SIGHUP, &sa, &previousSighup) == -1) {
74 LOG(FATAL) <<
"Cannot install SIGHUP handler.";
76 if (sigaction(SIGINT, &sa, &previousSigint) == -1) {
77 LOG(FATAL) <<
"Cannot install SIGINT handler.";
82 void unhookHandler() {
83 if (--hookedUpCount > 0) {
88 sa.sa_handler = SIG_DFL;
90 sa.sa_flags = SA_RESTART;
92 sigfillset(&sa.sa_mask);
94 if (sigaction(SIGHUP, &previousSighup,
nullptr) == -1) {
95 LOG(FATAL) <<
"Cannot uninstall SIGHUP handler.";
97 if (sigaction(SIGINT, &previousSigint,
nullptr) == -1) {
98 LOG(FATAL) <<
"Cannot uninstall SIGINT handler.";
102 #if defined(CAFFE2_SUPPORTS_FATAL_SIGNAL_HANDLERS) 104 std::mutex fatalSignalHandlersInstallationMutex;
105 bool fatalSignalHandlersInstalled;
108 struct sigaction previousSigusr2;
111 std::atomic<bool> fatalSignalReceived(
false);
114 const char* fatalSignalName(
"<UNKNOWN>");
119 pthread_cond_t writingCond = PTHREAD_COND_INITIALIZER;
120 pthread_mutex_t writingMutex = PTHREAD_MUTEX_INITIALIZER;
125 struct sigaction previous;
126 } kSignalHandlers[] = {
127 {
"SIGABRT", SIGABRT, {} },
128 {
"SIGINT", SIGINT, {} },
129 {
"SIGILL", SIGILL, {} },
130 {
"SIGFPE", SIGFPE, {} },
131 {
"SIGBUS", SIGBUS, {} },
132 {
"SIGSEGV", SIGSEGV, {} },
136 struct sigaction* getPreviousSigaction(
int signum) {
137 for (
auto handler = kSignalHandlers; handler->name !=
nullptr; handler++) {
138 if (handler->signum == signum) {
139 return &handler->previous;
145 const char* getSignalName(
int signum) {
146 for (
auto handler = kSignalHandlers; handler->name !=
nullptr; handler++) {
147 if (handler->signum == signum) {
148 return handler->name;
154 _Unwind_Reason_Code unwinder(
struct _Unwind_Context* context,
void* userInfo) {
155 auto& pcs = *
reinterpret_cast<std::vector<uintptr_t>*
>(userInfo);
156 pcs.push_back(_Unwind_GetIP(context));
157 return _URC_NO_REASON;
160 std::vector<uintptr_t> getBacktrace() {
161 std::vector<uintptr_t> pcs;
162 _Unwind_Backtrace(unwinder, &pcs);
166 void printBlobSizes() {
171 void printStacktrace() {
172 std::vector<uintptr_t> pcs = getBacktrace();
175 for (uintptr_t pcAddr : pcs) {
176 const void* pc =
reinterpret_cast<const void*
>(pcAddr);
177 const char* path =
nullptr;
178 const char* name =
"???";
179 char* demangled =
nullptr;
182 std::cerr <<
"[" << i <<
"] ";
183 if (dladdr(pc, &info)) {
184 path = info.dli_fname;
185 name = info.dli_sname ?:
"???";
186 offset =
reinterpret_cast<uintptr_t
>(pc) -
187 reinterpret_cast<uintptr_t>(info.dli_saddr);
190 demangled = abi::__cxa_demangle(name,
nullptr,
nullptr, &status);
197 std::cerr <<
"+" <<
reinterpret_cast<void*
>(offset);
199 std::cerr <<
"(" << pc <<
")";
201 std::cerr <<
" in " << path;
203 std::cerr << std::endl;
211 void callPreviousSignalHandler(
212 struct sigaction* action,
216 if (!action->sa_handler) {
219 if ((action->sa_flags & SA_SIGINFO) == SA_SIGINFO) {
220 action->sa_sigaction(signum, info, ctx);
222 action->sa_handler(signum);
227 void stacktraceSignalHandler(
bool needsLock) {
229 pthread_mutex_lock(&writingMutex);
231 pid_t tid = syscall(SYS_gettid);
232 std::cerr << fatalSignalName <<
"(" << fatalSignum <<
"), Thread " << tid
233 <<
": " << std::endl;
235 std::cerr << std::endl;
237 pthread_mutex_unlock(&writingMutex);
238 pthread_cond_signal(&writingCond);
243 void fatalSignalHandler(
int signum) {
245 const char* name = getSignalName(signum);
249 if (fatalSignalReceived) {
254 fatalSignalReceived =
true;
256 fatalSignum = signum;
257 fatalSignalName = name;
260 DIR* procDir = opendir(
"/proc/self/task");
262 pid_t pid = getpid();
263 pid_t currentTid = syscall(SYS_gettid);
264 struct dirent* entry;
265 pthread_mutex_lock(&writingMutex);
266 while ((entry = readdir(procDir)) !=
nullptr) {
267 if (entry->d_name[0] ==
'.') {
270 pid_t tid = atoi(entry->d_name);
274 if (tid != currentTid) {
275 syscall(SYS_tgkill, pid, tid, SIGUSR2);
276 pthread_cond_wait(&writingCond, &writingMutex);
278 stacktraceSignalHandler(
false);
281 pthread_mutex_unlock(&writingMutex);
283 perror(
"Failed to open /proc/self/task");
286 sigaction(signum, getPreviousSigaction(signum),
nullptr);
291 void stacktraceSignalHandler(
int signum, siginfo_t* info,
void* ctx) {
292 if (fatalSignalReceived) {
293 stacktraceSignalHandler(
true);
297 callPreviousSignalHandler(&previousSigusr2, signum, info, ctx);
306 void installFatalSignalHandlers() {
307 std::lock_guard<std::mutex> locker(fatalSignalHandlersInstallationMutex);
308 if (fatalSignalHandlersInstalled) {
311 fatalSignalHandlersInstalled =
true;
313 sigemptyset(&sa.sa_mask);
316 sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
317 sa.sa_handler = ::fatalSignalHandler;
318 for (
auto* handler = kSignalHandlers; handler->name !=
nullptr; handler++) {
319 if (sigaction(handler->signum, &sa, &handler->previous)) {
320 std::string str(
"Failed to add ");
321 str += handler->name;
326 sa.sa_sigaction = ::stacktraceSignalHandler;
327 if (sigaction(SIGUSR2, &sa, &::previousSigusr2)) {
328 perror(
"Failed to add SIGUSR2 handler!");
332 void uninstallFatalSignalHandlers() {
333 std::lock_guard<std::mutex> locker(fatalSignalHandlersInstallationMutex);
334 if (!fatalSignalHandlersInstalled) {
337 fatalSignalHandlersInstalled =
false;
338 for (
auto* handler = kSignalHandlers; handler->name !=
nullptr; handler++) {
339 if (sigaction(handler->signum, &handler->previous,
nullptr)) {
340 std::string str(
"Failed to remove ");
341 str += handler->name;
345 handler->previous = {};
348 if (sigaction(SIGUSR2, &::previousSigusr2,
nullptr)) {
349 perror(
"Failed to add SIGUSR2 handler!");
351 ::previousSigusr2 = {};
354 #endif // defined(CAFFE2_SUPPORTS_FATAL_SIGNAL_HANDLERS) 358 #if defined(CAFFE2_SUPPORTS_FATAL_SIGNAL_HANDLERS) 360 caffe2_print_stacktraces,
362 "If set, prints stacktraces when a fatal signal is raised.");
367 SignalHandler::SignalHandler(
368 SignalHandler::Action SIGINT_action,
369 SignalHandler::Action SIGHUP_action)
370 : SIGINT_action_(SIGINT_action),
371 SIGHUP_action_(SIGHUP_action),
372 my_sigint_count_(sigintCount),
373 my_sighup_count_(sighupCount) {
377 SignalHandler::~SignalHandler() {
383 bool SignalHandler::GotSIGINT() {
384 uint64_t count = sigintCount;
385 bool result = (count != my_sigint_count_);
386 my_sigint_count_ = count;
392 bool SignalHandler::GotSIGHUP() {
393 uint64_t count = sighupCount;
394 bool result = (count != my_sighup_count_);
395 my_sighup_count_ = count;
399 SignalHandler::Action SignalHandler::CheckForSignals() {
401 return SIGHUP_action_;
404 return SIGINT_action_;
406 return SignalHandler::Action::NONE;
409 #if defined(CAFFE2_SUPPORTS_FATAL_SIGNAL_HANDLERS) 410 void setPrintStackTracesOnFatalSignal(
bool print) {
412 installFatalSignalHandlers();
414 uninstallFatalSignalHandlers();
417 bool printStackTracesOnFatalSignal() {
418 std::lock_guard<std::mutex> locker(fatalSignalHandlersInstallationMutex);
419 return fatalSignalHandlersInstalled;
423 bool Caffe2InitFatalSignalHandler(
int*,
char***) {
424 if (FLAGS_caffe2_print_stacktraces) {
425 setPrintStackTracesOnFatalSignal(
true);
430 REGISTER_CAFFE2_INIT_FUNCTION(
431 Caffe2InitFatalSignalHandler,
432 &Caffe2InitFatalSignalHandler,
433 "Inits signal handlers for fatal signals so we can see what if" 434 " caffe2_print_stacktraces is set.");
437 #endif // defined(CAFFE2_SUPPORTS_FATAL_SIGNAL_HANDLERS) 440 #else // defined(CAFFE2_SUPPORTS_SIGNAL_HANDLER) 445 SignalHandler::SignalHandler(
446 SignalHandler::Action SIGINT_action,
447 SignalHandler::Action SIGHUP_action) {}
448 SignalHandler::~SignalHandler() {}
449 bool SignalHandler::GotSIGINT() {
452 bool SignalHandler::GotSIGHUP() {
455 SignalHandler::Action SignalHandler::CheckForSignals() {
456 return SignalHandler::Action::NONE;
460 #endif // defined(CAFFE2_SUPPORTS_SIGNAL_HANDLER) Workspace is a class that holds all the related objects created during runtime: (1) all blobs...
static void ForEach(F f)
Applies a function f on each workspace that currently exists.
A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...