1 | #pragma once |
---|---|
2 | |
3 | #include <atomic> |
4 | #include <csignal> |
5 | #include <mutex> |
6 | |
7 | #include <c10/macros/Export.h> |
8 | #include <c10/util/Logging.h> |
9 | |
10 | #if defined(__APPLE__) |
11 | #define C10_SUPPORTS_SIGNAL_HANDLER |
12 | #elif defined(__linux__) && !defined(C10_DISABLE_SIGNAL_HANDLERS) |
13 | #define C10_SUPPORTS_FATAL_SIGNAL_HANDLERS |
14 | #define C10_SUPPORTS_SIGNAL_HANDLER |
15 | #endif |
16 | |
17 | #if defined(C10_SUPPORTS_FATAL_SIGNAL_HANDLERS) |
18 | #include <pthread.h> |
19 | #endif |
20 | |
21 | namespace c10 { |
22 | |
23 | class C10_API SignalHandler { |
24 | public: |
25 | enum class Action { NONE, STOP }; |
26 | |
27 | // Constructor. Specify what action to take when a signal is received. |
28 | SignalHandler(Action SIGINT_action, Action SIGHUP_action); |
29 | ~SignalHandler(); |
30 | |
31 | Action CheckForSignals(); |
32 | |
33 | bool GotSIGINT(); |
34 | bool GotSIGHUP(); |
35 | |
36 | Action SIGINT_action_; |
37 | Action SIGHUP_action_; |
38 | unsigned long my_sigint_count_; |
39 | unsigned long my_sighup_count_; |
40 | }; |
41 | |
42 | #if defined(C10_SUPPORTS_FATAL_SIGNAL_HANDLERS) |
43 | class C10_API FatalSignalHandler { |
44 | // This works by setting up certain fatal signal handlers. Previous fatal |
45 | // signal handlers will still be called when the signal is raised. Defaults |
46 | // to being off. |
47 | public: |
48 | C10_API void setPrintStackTracesOnFatalSignal(bool print); |
49 | C10_API bool printStackTracesOnFatalSignal(); |
50 | static FatalSignalHandler& getInstance(); |
51 | virtual ~FatalSignalHandler(); |
52 | |
53 | protected: |
54 | explicit FatalSignalHandler(); |
55 | |
56 | private: |
57 | void installFatalSignalHandlers(); |
58 | void uninstallFatalSignalHandlers(); |
59 | static void fatalSignalHandlerStatic(int signum); |
60 | void fatalSignalHandler(int signum); |
61 | virtual void fatalSignalHandlerPostProcess(); |
62 | struct sigaction* getPreviousSigaction(int signum); |
63 | const char* getSignalName(int signum); |
64 | void callPreviousSignalHandler( |
65 | struct sigaction* action, |
66 | int signum, |
67 | siginfo_t* info, |
68 | void* ctx); |
69 | void stacktraceSignalHandler(bool needsLock); |
70 | static void stacktraceSignalHandlerStatic( |
71 | int signum, |
72 | siginfo_t* info, |
73 | void* ctx); |
74 | void stacktraceSignalHandler(int signum, siginfo_t* info, void* ctx); |
75 | |
76 | // The mutex protects the bool. |
77 | std::mutex fatalSignalHandlersInstallationMutex; |
78 | bool fatalSignalHandlersInstalled; |
79 | // We need to hold a reference to call the previous SIGUSR2 handler in case |
80 | // we didn't signal it |
81 | struct sigaction previousSigusr2 {}; |
82 | // Flag dictating whether the SIGUSR2 handler falls back to previous handlers |
83 | // or is intercepted in order to print a stack trace. |
84 | std::atomic<bool> fatalSignalReceived; |
85 | // Global state set when a fatal signal is received so that backtracing |
86 | // threads know why they're printing a stacktrace. |
87 | const char* fatalSignalName; |
88 | int fatalSignum = -1; |
89 | // This wait condition is used to wait for other threads to finish writing |
90 | // their stack trace when in fatal sig handler (we can't use pthread_join |
91 | // because there's no way to convert from a tid to a pthread_t). |
92 | pthread_cond_t writingCond; |
93 | pthread_mutex_t writingMutex; |
94 | |
95 | struct signal_handler { |
96 | const char* name; |
97 | int signum; |
98 | struct sigaction previous; |
99 | }; |
100 | |
101 | static signal_handler kSignalHandlers[]; |
102 | }; |
103 | |
104 | #endif // defined(C10_SUPPORTS_SIGNAL_HANDLER) |
105 | |
106 | } // namespace c10 |
107 |