xref: /aosp_15_r20/external/pytorch/c10/util/signal_handler.cpp (revision da0073e96a02ea20f0ac840b70461e3646d07c45)
1*da0073e9SAndroid Build Coastguard Worker #include <c10/util/Backtrace.h>
2*da0073e9SAndroid Build Coastguard Worker #include <c10/util/Logging.h>
3*da0073e9SAndroid Build Coastguard Worker #include <c10/util/signal_handler.h>
4*da0073e9SAndroid Build Coastguard Worker 
5*da0073e9SAndroid Build Coastguard Worker #if defined(C10_SUPPORTS_SIGNAL_HANDLER)
6*da0073e9SAndroid Build Coastguard Worker 
7*da0073e9SAndroid Build Coastguard Worker // Normal signal handler implementation.
8*da0073e9SAndroid Build Coastguard Worker #include <dirent.h>
9*da0073e9SAndroid Build Coastguard Worker #include <fmt/core.h>
10*da0073e9SAndroid Build Coastguard Worker #include <sys/syscall.h>
11*da0073e9SAndroid Build Coastguard Worker #include <unistd.h>
12*da0073e9SAndroid Build Coastguard Worker 
13*da0073e9SAndroid Build Coastguard Worker #include <atomic>
14*da0073e9SAndroid Build Coastguard Worker #include <chrono>
15*da0073e9SAndroid Build Coastguard Worker #include <condition_variable>
16*da0073e9SAndroid Build Coastguard Worker #include <cstdint>
17*da0073e9SAndroid Build Coastguard Worker #include <cstdio>
18*da0073e9SAndroid Build Coastguard Worker #include <cstdlib>
19*da0073e9SAndroid Build Coastguard Worker #include <iostream>
20*da0073e9SAndroid Build Coastguard Worker #include <mutex>
21*da0073e9SAndroid Build Coastguard Worker 
22*da0073e9SAndroid Build Coastguard Worker #ifdef C10_ANDROID
23*da0073e9SAndroid Build Coastguard Worker #ifndef SYS_gettid
24*da0073e9SAndroid Build Coastguard Worker #define SYS_gettid __NR_gettid
25*da0073e9SAndroid Build Coastguard Worker #endif
26*da0073e9SAndroid Build Coastguard Worker #ifndef SYS_tgkill
27*da0073e9SAndroid Build Coastguard Worker #define SYS_tgkill __NR_tgkill
28*da0073e9SAndroid Build Coastguard Worker #endif
29*da0073e9SAndroid Build Coastguard Worker #endif
30*da0073e9SAndroid Build Coastguard Worker 
31*da0073e9SAndroid Build Coastguard Worker namespace {
32*da0073e9SAndroid Build Coastguard Worker 
33*da0073e9SAndroid Build Coastguard Worker struct sigaction previousSighup;
34*da0073e9SAndroid Build Coastguard Worker struct sigaction previousSigint;
35*da0073e9SAndroid Build Coastguard Worker std::atomic<int> sigintCount(0);
36*da0073e9SAndroid Build Coastguard Worker std::atomic<int> sighupCount(0);
37*da0073e9SAndroid Build Coastguard Worker std::atomic<int> hookedUpCount(0);
38*da0073e9SAndroid Build Coastguard Worker 
handleSignal(int signal)39*da0073e9SAndroid Build Coastguard Worker void handleSignal(int signal) {
40*da0073e9SAndroid Build Coastguard Worker   switch (signal) {
41*da0073e9SAndroid Build Coastguard Worker     // TODO: what if the previous handler uses sa_sigaction?
42*da0073e9SAndroid Build Coastguard Worker     case SIGHUP:
43*da0073e9SAndroid Build Coastguard Worker       sighupCount += 1;
44*da0073e9SAndroid Build Coastguard Worker       if (previousSighup.sa_handler) {
45*da0073e9SAndroid Build Coastguard Worker         previousSighup.sa_handler(signal);
46*da0073e9SAndroid Build Coastguard Worker       }
47*da0073e9SAndroid Build Coastguard Worker       break;
48*da0073e9SAndroid Build Coastguard Worker     case SIGINT:
49*da0073e9SAndroid Build Coastguard Worker       sigintCount += 1;
50*da0073e9SAndroid Build Coastguard Worker       if (previousSigint.sa_handler) {
51*da0073e9SAndroid Build Coastguard Worker         previousSigint.sa_handler(signal);
52*da0073e9SAndroid Build Coastguard Worker       }
53*da0073e9SAndroid Build Coastguard Worker       break;
54*da0073e9SAndroid Build Coastguard Worker   }
55*da0073e9SAndroid Build Coastguard Worker }
56*da0073e9SAndroid Build Coastguard Worker 
hookupHandler()57*da0073e9SAndroid Build Coastguard Worker void hookupHandler() {
58*da0073e9SAndroid Build Coastguard Worker   if (hookedUpCount++) {
59*da0073e9SAndroid Build Coastguard Worker     return;
60*da0073e9SAndroid Build Coastguard Worker   }
61*da0073e9SAndroid Build Coastguard Worker   struct sigaction sa {};
62*da0073e9SAndroid Build Coastguard Worker   // Setup the handler
63*da0073e9SAndroid Build Coastguard Worker   sa.sa_handler = &handleSignal;
64*da0073e9SAndroid Build Coastguard Worker   // Restart the system call, if at all possible
65*da0073e9SAndroid Build Coastguard Worker   sa.sa_flags = SA_RESTART;
66*da0073e9SAndroid Build Coastguard Worker   // Block every signal during the handler
67*da0073e9SAndroid Build Coastguard Worker   sigfillset(&sa.sa_mask);
68*da0073e9SAndroid Build Coastguard Worker   // Intercept SIGHUP and SIGINT
69*da0073e9SAndroid Build Coastguard Worker   if (sigaction(SIGHUP, &sa, &previousSighup) == -1) {
70*da0073e9SAndroid Build Coastguard Worker     LOG(FATAL) << "Cannot install SIGHUP handler.";
71*da0073e9SAndroid Build Coastguard Worker   }
72*da0073e9SAndroid Build Coastguard Worker   if (sigaction(SIGINT, &sa, &previousSigint) == -1) {
73*da0073e9SAndroid Build Coastguard Worker     LOG(FATAL) << "Cannot install SIGINT handler.";
74*da0073e9SAndroid Build Coastguard Worker   }
75*da0073e9SAndroid Build Coastguard Worker }
76*da0073e9SAndroid Build Coastguard Worker 
77*da0073e9SAndroid Build Coastguard Worker // Set the signal handlers to the default.
unhookHandler()78*da0073e9SAndroid Build Coastguard Worker void unhookHandler() {
79*da0073e9SAndroid Build Coastguard Worker   if (--hookedUpCount > 0) {
80*da0073e9SAndroid Build Coastguard Worker     return;
81*da0073e9SAndroid Build Coastguard Worker   }
82*da0073e9SAndroid Build Coastguard Worker   struct sigaction sa {};
83*da0073e9SAndroid Build Coastguard Worker   // Setup the sighub handler
84*da0073e9SAndroid Build Coastguard Worker   sa.sa_handler = SIG_DFL;
85*da0073e9SAndroid Build Coastguard Worker   // Restart the system call, if at all possible
86*da0073e9SAndroid Build Coastguard Worker   sa.sa_flags = SA_RESTART;
87*da0073e9SAndroid Build Coastguard Worker   // Block every signal during the handler
88*da0073e9SAndroid Build Coastguard Worker   sigfillset(&sa.sa_mask);
89*da0073e9SAndroid Build Coastguard Worker   // Intercept SIGHUP and SIGINT
90*da0073e9SAndroid Build Coastguard Worker   if (sigaction(SIGHUP, &previousSighup, nullptr) == -1) {
91*da0073e9SAndroid Build Coastguard Worker     LOG(FATAL) << "Cannot uninstall SIGHUP handler.";
92*da0073e9SAndroid Build Coastguard Worker   }
93*da0073e9SAndroid Build Coastguard Worker   if (sigaction(SIGINT, &previousSigint, nullptr) == -1) {
94*da0073e9SAndroid Build Coastguard Worker     LOG(FATAL) << "Cannot uninstall SIGINT handler.";
95*da0073e9SAndroid Build Coastguard Worker   }
96*da0073e9SAndroid Build Coastguard Worker }
97*da0073e9SAndroid Build Coastguard Worker 
98*da0073e9SAndroid Build Coastguard Worker } // namespace
99*da0073e9SAndroid Build Coastguard Worker 
100*da0073e9SAndroid Build Coastguard Worker namespace c10 {
101*da0073e9SAndroid Build Coastguard Worker 
102*da0073e9SAndroid Build Coastguard Worker #if defined(C10_SUPPORTS_FATAL_SIGNAL_HANDLERS)
103*da0073e9SAndroid Build Coastguard Worker 
getInstance()104*da0073e9SAndroid Build Coastguard Worker FatalSignalHandler& FatalSignalHandler::getInstance() {
105*da0073e9SAndroid Build Coastguard Worker   // Leaky singleton to avoid module destructor race.
106*da0073e9SAndroid Build Coastguard Worker   static FatalSignalHandler* handler = new FatalSignalHandler();
107*da0073e9SAndroid Build Coastguard Worker   return *handler;
108*da0073e9SAndroid Build Coastguard Worker }
109*da0073e9SAndroid Build Coastguard Worker 
110*da0073e9SAndroid Build Coastguard Worker FatalSignalHandler::~FatalSignalHandler() = default;
111*da0073e9SAndroid Build Coastguard Worker 
FatalSignalHandler()112*da0073e9SAndroid Build Coastguard Worker FatalSignalHandler::FatalSignalHandler()
113*da0073e9SAndroid Build Coastguard Worker     : fatalSignalHandlersInstalled(false),
114*da0073e9SAndroid Build Coastguard Worker       fatalSignalReceived(false),
115*da0073e9SAndroid Build Coastguard Worker       fatalSignalName("<UNKNOWN>"),
116*da0073e9SAndroid Build Coastguard Worker       writingCond(),
117*da0073e9SAndroid Build Coastguard Worker       writingMutex(),
118*da0073e9SAndroid Build Coastguard Worker       signalReceived(false) {}
119*da0073e9SAndroid Build Coastguard Worker 
120*da0073e9SAndroid Build Coastguard Worker // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays)
121*da0073e9SAndroid Build Coastguard Worker FatalSignalHandler::signal_handler FatalSignalHandler::kSignalHandlers[] = {
122*da0073e9SAndroid Build Coastguard Worker     {"SIGABRT", SIGABRT, {}},
123*da0073e9SAndroid Build Coastguard Worker     {"SIGINT", SIGINT, {}},
124*da0073e9SAndroid Build Coastguard Worker     {"SIGILL", SIGILL, {}},
125*da0073e9SAndroid Build Coastguard Worker     {"SIGFPE", SIGFPE, {}},
126*da0073e9SAndroid Build Coastguard Worker     {"SIGBUS", SIGBUS, {}},
127*da0073e9SAndroid Build Coastguard Worker     {"SIGSEGV", SIGSEGV, {}},
128*da0073e9SAndroid Build Coastguard Worker     {nullptr, 0, {}}};
129*da0073e9SAndroid Build Coastguard Worker 
getPreviousSigaction(int signum)130*da0073e9SAndroid Build Coastguard Worker struct sigaction* FatalSignalHandler::getPreviousSigaction(int signum) {
131*da0073e9SAndroid Build Coastguard Worker   for (auto handler = kSignalHandlers; handler->name != nullptr; handler++) {
132*da0073e9SAndroid Build Coastguard Worker     if (handler->signum == signum) {
133*da0073e9SAndroid Build Coastguard Worker       return &handler->previous;
134*da0073e9SAndroid Build Coastguard Worker     }
135*da0073e9SAndroid Build Coastguard Worker   }
136*da0073e9SAndroid Build Coastguard Worker   return nullptr;
137*da0073e9SAndroid Build Coastguard Worker }
138*da0073e9SAndroid Build Coastguard Worker 
getSignalName(int signum)139*da0073e9SAndroid Build Coastguard Worker const char* FatalSignalHandler::getSignalName(int signum) {
140*da0073e9SAndroid Build Coastguard Worker   for (auto handler = kSignalHandlers; handler->name != nullptr; handler++) {
141*da0073e9SAndroid Build Coastguard Worker     if (handler->signum == signum) {
142*da0073e9SAndroid Build Coastguard Worker       return handler->name;
143*da0073e9SAndroid Build Coastguard Worker     }
144*da0073e9SAndroid Build Coastguard Worker   }
145*da0073e9SAndroid Build Coastguard Worker   return nullptr;
146*da0073e9SAndroid Build Coastguard Worker }
147*da0073e9SAndroid Build Coastguard Worker 
callPreviousSignalHandler(struct sigaction * action,int signum,siginfo_t * info,void * ctx)148*da0073e9SAndroid Build Coastguard Worker void FatalSignalHandler::callPreviousSignalHandler(
149*da0073e9SAndroid Build Coastguard Worker     struct sigaction* action,
150*da0073e9SAndroid Build Coastguard Worker     int signum,
151*da0073e9SAndroid Build Coastguard Worker     siginfo_t* info,
152*da0073e9SAndroid Build Coastguard Worker     void* ctx) {
153*da0073e9SAndroid Build Coastguard Worker   if (!action->sa_handler) {
154*da0073e9SAndroid Build Coastguard Worker     return;
155*da0073e9SAndroid Build Coastguard Worker   }
156*da0073e9SAndroid Build Coastguard Worker   if ((action->sa_flags & SA_SIGINFO) == SA_SIGINFO) {
157*da0073e9SAndroid Build Coastguard Worker     action->sa_sigaction(signum, info, ctx);
158*da0073e9SAndroid Build Coastguard Worker   } else {
159*da0073e9SAndroid Build Coastguard Worker     action->sa_handler(signum);
160*da0073e9SAndroid Build Coastguard Worker   }
161*da0073e9SAndroid Build Coastguard Worker }
162*da0073e9SAndroid Build Coastguard Worker 
163*da0073e9SAndroid Build Coastguard Worker // needsLock signals whether we need to lock our writing mutex.
stacktraceSignalHandler(bool needsLock)164*da0073e9SAndroid Build Coastguard Worker void FatalSignalHandler::stacktraceSignalHandler(bool needsLock) {
165*da0073e9SAndroid Build Coastguard Worker   std::unique_lock<std::mutex> ul(writingMutex, std::defer_lock);
166*da0073e9SAndroid Build Coastguard Worker   if (needsLock) {
167*da0073e9SAndroid Build Coastguard Worker     ul.lock();
168*da0073e9SAndroid Build Coastguard Worker     signalReceived = true;
169*da0073e9SAndroid Build Coastguard Worker   }
170*da0073e9SAndroid Build Coastguard Worker   pid_t tid = static_cast<pid_t>(syscall(SYS_gettid));
171*da0073e9SAndroid Build Coastguard Worker   std::string backtrace = fmt::format(
172*da0073e9SAndroid Build Coastguard Worker       "{}({}), PID: {}, Thread {}: \n {}",
173*da0073e9SAndroid Build Coastguard Worker       fatalSignalName,
174*da0073e9SAndroid Build Coastguard Worker       fatalSignum,
175*da0073e9SAndroid Build Coastguard Worker       ::getpid(),
176*da0073e9SAndroid Build Coastguard Worker       tid,
177*da0073e9SAndroid Build Coastguard Worker       c10::get_backtrace());
178*da0073e9SAndroid Build Coastguard Worker   std::cerr << backtrace << std::endl;
179*da0073e9SAndroid Build Coastguard Worker   if (needsLock) {
180*da0073e9SAndroid Build Coastguard Worker     ul.unlock();
181*da0073e9SAndroid Build Coastguard Worker     writingCond.notify_all();
182*da0073e9SAndroid Build Coastguard Worker   }
183*da0073e9SAndroid Build Coastguard Worker }
184*da0073e9SAndroid Build Coastguard Worker 
fatalSignalHandlerPostProcess()185*da0073e9SAndroid Build Coastguard Worker void FatalSignalHandler::fatalSignalHandlerPostProcess() {}
186*da0073e9SAndroid Build Coastguard Worker 
fatalSignalHandlerStatic(int signum)187*da0073e9SAndroid Build Coastguard Worker void FatalSignalHandler::fatalSignalHandlerStatic(int signum) {
188*da0073e9SAndroid Build Coastguard Worker   getInstance().fatalSignalHandler(signum);
189*da0073e9SAndroid Build Coastguard Worker }
190*da0073e9SAndroid Build Coastguard Worker 
191*da0073e9SAndroid Build Coastguard Worker // Our fatal signal entry point
fatalSignalHandler(int signum)192*da0073e9SAndroid Build Coastguard Worker void FatalSignalHandler::fatalSignalHandler(int signum) {
193*da0073e9SAndroid Build Coastguard Worker   // Check if this is a proper signal that we declared above.
194*da0073e9SAndroid Build Coastguard Worker   const char* name = getSignalName(signum);
195*da0073e9SAndroid Build Coastguard Worker   if (!name) {
196*da0073e9SAndroid Build Coastguard Worker     return;
197*da0073e9SAndroid Build Coastguard Worker   }
198*da0073e9SAndroid Build Coastguard Worker   if (fatalSignalReceived) {
199*da0073e9SAndroid Build Coastguard Worker     return;
200*da0073e9SAndroid Build Coastguard Worker   }
201*da0073e9SAndroid Build Coastguard Worker   // Set the flag so that our SIGUSR2 handler knows that we're aborting and
202*da0073e9SAndroid Build Coastguard Worker   // that it should intercept any SIGUSR2 signal.
203*da0073e9SAndroid Build Coastguard Worker   fatalSignalReceived = true;
204*da0073e9SAndroid Build Coastguard Worker   // Set state for other threads.
205*da0073e9SAndroid Build Coastguard Worker   fatalSignum = signum;
206*da0073e9SAndroid Build Coastguard Worker   fatalSignalName = name;
207*da0073e9SAndroid Build Coastguard Worker   // Linux doesn't have a nice userland API for enumerating threads so we
208*da0073e9SAndroid Build Coastguard Worker   // need to use the proc pseudo-filesystem.
209*da0073e9SAndroid Build Coastguard Worker   DIR* procDir = opendir("/proc/self/task");
210*da0073e9SAndroid Build Coastguard Worker   if (procDir) {
211*da0073e9SAndroid Build Coastguard Worker     pid_t pid = getpid();
212*da0073e9SAndroid Build Coastguard Worker     pid_t currentTid = static_cast<pid_t>(syscall(SYS_gettid));
213*da0073e9SAndroid Build Coastguard Worker     struct dirent* entry = nullptr;
214*da0073e9SAndroid Build Coastguard Worker     std::unique_lock<std::mutex> ul(writingMutex);
215*da0073e9SAndroid Build Coastguard Worker     while ((entry = readdir(procDir)) != nullptr) {
216*da0073e9SAndroid Build Coastguard Worker       if (entry->d_name[0] == '.') {
217*da0073e9SAndroid Build Coastguard Worker         continue;
218*da0073e9SAndroid Build Coastguard Worker       }
219*da0073e9SAndroid Build Coastguard Worker       pid_t tid = atoi(entry->d_name);
220*da0073e9SAndroid Build Coastguard Worker       // If we've found the current thread then we'll jump into the SIGUSR2
221*da0073e9SAndroid Build Coastguard Worker       // handler instead of signaling to avoid deadlocking.
222*da0073e9SAndroid Build Coastguard Worker       if (tid != currentTid) {
223*da0073e9SAndroid Build Coastguard Worker         signalReceived = false;
224*da0073e9SAndroid Build Coastguard Worker         syscall(SYS_tgkill, pid, tid, SIGUSR2);
225*da0073e9SAndroid Build Coastguard Worker         auto now = std::chrono::system_clock::now();
226*da0073e9SAndroid Build Coastguard Worker         using namespace std::chrono_literals;
227*da0073e9SAndroid Build Coastguard Worker         // we use wait_until instead of wait because on ROCm there was
228*da0073e9SAndroid Build Coastguard Worker         // a single thread that wouldn't receive the SIGUSR2
229*da0073e9SAndroid Build Coastguard Worker         if (std::cv_status::timeout == writingCond.wait_until(ul, now + 2s)) {
230*da0073e9SAndroid Build Coastguard Worker           if (!signalReceived) {
231*da0073e9SAndroid Build Coastguard Worker             std::cerr << "signal lost waiting for stacktrace " << pid << ":"
232*da0073e9SAndroid Build Coastguard Worker                       << tid << std::endl;
233*da0073e9SAndroid Build Coastguard Worker             break;
234*da0073e9SAndroid Build Coastguard Worker           }
235*da0073e9SAndroid Build Coastguard Worker         }
236*da0073e9SAndroid Build Coastguard Worker       } else {
237*da0073e9SAndroid Build Coastguard Worker         stacktraceSignalHandler(false);
238*da0073e9SAndroid Build Coastguard Worker       }
239*da0073e9SAndroid Build Coastguard Worker     }
240*da0073e9SAndroid Build Coastguard Worker   } else {
241*da0073e9SAndroid Build Coastguard Worker     perror("Failed to open /proc/self/task");
242*da0073e9SAndroid Build Coastguard Worker   }
243*da0073e9SAndroid Build Coastguard Worker   fatalSignalHandlerPostProcess();
244*da0073e9SAndroid Build Coastguard Worker   sigaction(signum, getPreviousSigaction(signum), nullptr);
245*da0073e9SAndroid Build Coastguard Worker   raise(signum);
246*da0073e9SAndroid Build Coastguard Worker }
247*da0073e9SAndroid Build Coastguard Worker 
248*da0073e9SAndroid Build Coastguard Worker // Our SIGUSR2 entry point
stacktraceSignalHandlerStatic(int signum,siginfo_t * info,void * ctx)249*da0073e9SAndroid Build Coastguard Worker void FatalSignalHandler::stacktraceSignalHandlerStatic(
250*da0073e9SAndroid Build Coastguard Worker     int signum,
251*da0073e9SAndroid Build Coastguard Worker     siginfo_t* info,
252*da0073e9SAndroid Build Coastguard Worker     void* ctx) {
253*da0073e9SAndroid Build Coastguard Worker   getInstance().stacktraceSignalHandler(signum, info, ctx);
254*da0073e9SAndroid Build Coastguard Worker }
255*da0073e9SAndroid Build Coastguard Worker 
stacktraceSignalHandler(int signum,siginfo_t * info,void * ctx)256*da0073e9SAndroid Build Coastguard Worker void FatalSignalHandler::stacktraceSignalHandler(
257*da0073e9SAndroid Build Coastguard Worker     int signum,
258*da0073e9SAndroid Build Coastguard Worker     siginfo_t* info,
259*da0073e9SAndroid Build Coastguard Worker     void* ctx) {
260*da0073e9SAndroid Build Coastguard Worker   if (fatalSignalReceived) {
261*da0073e9SAndroid Build Coastguard Worker     stacktraceSignalHandler(true);
262*da0073e9SAndroid Build Coastguard Worker   } else {
263*da0073e9SAndroid Build Coastguard Worker     // We don't want to actually change the signal handler as we want to
264*da0073e9SAndroid Build Coastguard Worker     // remain the signal handler so that we may get the usr2 signal later.
265*da0073e9SAndroid Build Coastguard Worker     callPreviousSignalHandler(&previousSigusr2, signum, info, ctx);
266*da0073e9SAndroid Build Coastguard Worker   }
267*da0073e9SAndroid Build Coastguard Worker }
268*da0073e9SAndroid Build Coastguard Worker 
269*da0073e9SAndroid Build Coastguard Worker // Installs SIGABRT signal handler so that we get stack traces
270*da0073e9SAndroid Build Coastguard Worker // from every thread on SIGABRT caused exit. Also installs SIGUSR2 handler
271*da0073e9SAndroid Build Coastguard Worker // so that threads can communicate with each other (be sure if you use SIGUSR2)
272*da0073e9SAndroid Build Coastguard Worker // to install your handler before initing caffe2 (we properly fall back to
273*da0073e9SAndroid Build Coastguard Worker // the previous handler if we didn't initiate the SIGUSR2).
installFatalSignalHandlers()274*da0073e9SAndroid Build Coastguard Worker void FatalSignalHandler::installFatalSignalHandlers() {
275*da0073e9SAndroid Build Coastguard Worker   std::lock_guard<std::mutex> locker(fatalSignalHandlersInstallationMutex);
276*da0073e9SAndroid Build Coastguard Worker   if (fatalSignalHandlersInstalled) {
277*da0073e9SAndroid Build Coastguard Worker     return;
278*da0073e9SAndroid Build Coastguard Worker   }
279*da0073e9SAndroid Build Coastguard Worker   fatalSignalHandlersInstalled = true;
280*da0073e9SAndroid Build Coastguard Worker   struct sigaction sa {};
281*da0073e9SAndroid Build Coastguard Worker   sigemptyset(&sa.sa_mask);
282*da0073e9SAndroid Build Coastguard Worker   // Since we'll be in an exiting situation it's possible there's memory
283*da0073e9SAndroid Build Coastguard Worker   // corruption, so make our own stack just in case.
284*da0073e9SAndroid Build Coastguard Worker   sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
285*da0073e9SAndroid Build Coastguard Worker   sa.sa_handler = FatalSignalHandler::fatalSignalHandlerStatic;
286*da0073e9SAndroid Build Coastguard Worker   for (auto* handler = kSignalHandlers; handler->name != nullptr; handler++) {
287*da0073e9SAndroid Build Coastguard Worker     if (sigaction(handler->signum, &sa, &handler->previous)) {
288*da0073e9SAndroid Build Coastguard Worker       std::string str("Failed to add ");
289*da0073e9SAndroid Build Coastguard Worker       str += handler->name;
290*da0073e9SAndroid Build Coastguard Worker       str += " handler!";
291*da0073e9SAndroid Build Coastguard Worker       perror(str.c_str());
292*da0073e9SAndroid Build Coastguard Worker     }
293*da0073e9SAndroid Build Coastguard Worker   }
294*da0073e9SAndroid Build Coastguard Worker   sa.sa_sigaction = FatalSignalHandler::stacktraceSignalHandlerStatic;
295*da0073e9SAndroid Build Coastguard Worker   if (sigaction(SIGUSR2, &sa, &previousSigusr2)) {
296*da0073e9SAndroid Build Coastguard Worker     perror("Failed to add SIGUSR2 handler!");
297*da0073e9SAndroid Build Coastguard Worker   }
298*da0073e9SAndroid Build Coastguard Worker }
299*da0073e9SAndroid Build Coastguard Worker 
uninstallFatalSignalHandlers()300*da0073e9SAndroid Build Coastguard Worker void FatalSignalHandler::uninstallFatalSignalHandlers() {
301*da0073e9SAndroid Build Coastguard Worker   std::lock_guard<std::mutex> locker(fatalSignalHandlersInstallationMutex);
302*da0073e9SAndroid Build Coastguard Worker   if (!fatalSignalHandlersInstalled) {
303*da0073e9SAndroid Build Coastguard Worker     return;
304*da0073e9SAndroid Build Coastguard Worker   }
305*da0073e9SAndroid Build Coastguard Worker   fatalSignalHandlersInstalled = false;
306*da0073e9SAndroid Build Coastguard Worker   for (auto* handler = kSignalHandlers; handler->name != nullptr; handler++) {
307*da0073e9SAndroid Build Coastguard Worker     if (sigaction(handler->signum, &handler->previous, nullptr)) {
308*da0073e9SAndroid Build Coastguard Worker       std::string str("Failed to remove ");
309*da0073e9SAndroid Build Coastguard Worker       str += handler->name;
310*da0073e9SAndroid Build Coastguard Worker       str += " handler!";
311*da0073e9SAndroid Build Coastguard Worker       perror(str.c_str());
312*da0073e9SAndroid Build Coastguard Worker     } else {
313*da0073e9SAndroid Build Coastguard Worker       handler->previous = {};
314*da0073e9SAndroid Build Coastguard Worker     }
315*da0073e9SAndroid Build Coastguard Worker   }
316*da0073e9SAndroid Build Coastguard Worker   if (sigaction(SIGUSR2, &previousSigusr2, nullptr)) {
317*da0073e9SAndroid Build Coastguard Worker     perror("Failed to add SIGUSR2 handler!");
318*da0073e9SAndroid Build Coastguard Worker   } else {
319*da0073e9SAndroid Build Coastguard Worker     previousSigusr2 = {};
320*da0073e9SAndroid Build Coastguard Worker   }
321*da0073e9SAndroid Build Coastguard Worker }
322*da0073e9SAndroid Build Coastguard Worker #endif // defined(C10_SUPPORTS_FATAL_SIGNAL_HANDLERS)
323*da0073e9SAndroid Build Coastguard Worker 
SignalHandler(SignalHandler::Action SIGINT_action,SignalHandler::Action SIGHUP_action)324*da0073e9SAndroid Build Coastguard Worker SignalHandler::SignalHandler(
325*da0073e9SAndroid Build Coastguard Worker     SignalHandler::Action SIGINT_action,
326*da0073e9SAndroid Build Coastguard Worker     SignalHandler::Action SIGHUP_action)
327*da0073e9SAndroid Build Coastguard Worker     : SIGINT_action_(SIGINT_action),
328*da0073e9SAndroid Build Coastguard Worker       SIGHUP_action_(SIGHUP_action),
329*da0073e9SAndroid Build Coastguard Worker       my_sigint_count_(sigintCount),
330*da0073e9SAndroid Build Coastguard Worker       my_sighup_count_(sighupCount) {
331*da0073e9SAndroid Build Coastguard Worker   hookupHandler();
332*da0073e9SAndroid Build Coastguard Worker }
333*da0073e9SAndroid Build Coastguard Worker 
~SignalHandler()334*da0073e9SAndroid Build Coastguard Worker SignalHandler::~SignalHandler() {
335*da0073e9SAndroid Build Coastguard Worker   unhookHandler();
336*da0073e9SAndroid Build Coastguard Worker }
337*da0073e9SAndroid Build Coastguard Worker 
338*da0073e9SAndroid Build Coastguard Worker // Return true iff a SIGINT has been received since the last time this
339*da0073e9SAndroid Build Coastguard Worker // function was called.
GotSIGINT()340*da0073e9SAndroid Build Coastguard Worker bool SignalHandler::GotSIGINT() {
341*da0073e9SAndroid Build Coastguard Worker   uint64_t count = sigintCount;
342*da0073e9SAndroid Build Coastguard Worker   uint64_t localCount = my_sigint_count_.exchange(count);
343*da0073e9SAndroid Build Coastguard Worker   return (localCount != count);
344*da0073e9SAndroid Build Coastguard Worker }
345*da0073e9SAndroid Build Coastguard Worker 
346*da0073e9SAndroid Build Coastguard Worker // Return true iff a SIGHUP has been received since the last time this
347*da0073e9SAndroid Build Coastguard Worker // function was called.
GotSIGHUP()348*da0073e9SAndroid Build Coastguard Worker bool SignalHandler::GotSIGHUP() {
349*da0073e9SAndroid Build Coastguard Worker   uint64_t count = sighupCount;
350*da0073e9SAndroid Build Coastguard Worker   uint64_t localCount = my_sighup_count_.exchange(count);
351*da0073e9SAndroid Build Coastguard Worker   return (localCount != count);
352*da0073e9SAndroid Build Coastguard Worker }
353*da0073e9SAndroid Build Coastguard Worker 
CheckForSignals()354*da0073e9SAndroid Build Coastguard Worker SignalHandler::Action SignalHandler::CheckForSignals() {
355*da0073e9SAndroid Build Coastguard Worker   if (GotSIGHUP()) {
356*da0073e9SAndroid Build Coastguard Worker     return SIGHUP_action_;
357*da0073e9SAndroid Build Coastguard Worker   }
358*da0073e9SAndroid Build Coastguard Worker   if (GotSIGINT()) {
359*da0073e9SAndroid Build Coastguard Worker     return SIGINT_action_;
360*da0073e9SAndroid Build Coastguard Worker   }
361*da0073e9SAndroid Build Coastguard Worker   return SignalHandler::Action::NONE;
362*da0073e9SAndroid Build Coastguard Worker }
363*da0073e9SAndroid Build Coastguard Worker 
364*da0073e9SAndroid Build Coastguard Worker #if defined(C10_SUPPORTS_FATAL_SIGNAL_HANDLERS)
setPrintStackTracesOnFatalSignal(bool print)365*da0073e9SAndroid Build Coastguard Worker void FatalSignalHandler::setPrintStackTracesOnFatalSignal(bool print) {
366*da0073e9SAndroid Build Coastguard Worker   if (print) {
367*da0073e9SAndroid Build Coastguard Worker     installFatalSignalHandlers();
368*da0073e9SAndroid Build Coastguard Worker   } else {
369*da0073e9SAndroid Build Coastguard Worker     uninstallFatalSignalHandlers();
370*da0073e9SAndroid Build Coastguard Worker   }
371*da0073e9SAndroid Build Coastguard Worker }
printStackTracesOnFatalSignal()372*da0073e9SAndroid Build Coastguard Worker bool FatalSignalHandler::printStackTracesOnFatalSignal() {
373*da0073e9SAndroid Build Coastguard Worker   std::lock_guard<std::mutex> locker(fatalSignalHandlersInstallationMutex);
374*da0073e9SAndroid Build Coastguard Worker   return fatalSignalHandlersInstalled;
375*da0073e9SAndroid Build Coastguard Worker }
376*da0073e9SAndroid Build Coastguard Worker 
377*da0073e9SAndroid Build Coastguard Worker #endif // defined(C10_SUPPORTS_FATAL_SIGNAL_HANDLERS)
378*da0073e9SAndroid Build Coastguard Worker } // namespace c10
379*da0073e9SAndroid Build Coastguard Worker 
380*da0073e9SAndroid Build Coastguard Worker #else // defined(C10_SUPPORTS_SIGNAL_HANDLER)
381*da0073e9SAndroid Build Coastguard Worker 
382*da0073e9SAndroid Build Coastguard Worker // TODO: Currently we do not support signal handling in non-Linux yet - below is
383*da0073e9SAndroid Build Coastguard Worker // a minimal implementation that makes things compile.
384*da0073e9SAndroid Build Coastguard Worker namespace c10 {
SignalHandler(SignalHandler::Action SIGINT_action,SignalHandler::Action SIGHUP_action)385*da0073e9SAndroid Build Coastguard Worker SignalHandler::SignalHandler(
386*da0073e9SAndroid Build Coastguard Worker     SignalHandler::Action SIGINT_action,
387*da0073e9SAndroid Build Coastguard Worker     SignalHandler::Action SIGHUP_action) {
388*da0073e9SAndroid Build Coastguard Worker   SIGINT_action_ = SIGINT_action;
389*da0073e9SAndroid Build Coastguard Worker   SIGHUP_action_ = SIGHUP_action;
390*da0073e9SAndroid Build Coastguard Worker   my_sigint_count_ = 0;
391*da0073e9SAndroid Build Coastguard Worker   my_sighup_count_ = 0;
392*da0073e9SAndroid Build Coastguard Worker }
~SignalHandler()393*da0073e9SAndroid Build Coastguard Worker SignalHandler::~SignalHandler() {}
GotSIGINT()394*da0073e9SAndroid Build Coastguard Worker bool SignalHandler::GotSIGINT() {
395*da0073e9SAndroid Build Coastguard Worker   return false;
396*da0073e9SAndroid Build Coastguard Worker }
GotSIGHUP()397*da0073e9SAndroid Build Coastguard Worker bool SignalHandler::GotSIGHUP() {
398*da0073e9SAndroid Build Coastguard Worker   return false;
399*da0073e9SAndroid Build Coastguard Worker }
CheckForSignals()400*da0073e9SAndroid Build Coastguard Worker SignalHandler::Action SignalHandler::CheckForSignals() {
401*da0073e9SAndroid Build Coastguard Worker   return SignalHandler::Action::NONE;
402*da0073e9SAndroid Build Coastguard Worker }
403*da0073e9SAndroid Build Coastguard Worker } // namespace c10
404*da0073e9SAndroid Build Coastguard Worker 
405*da0073e9SAndroid Build Coastguard Worker #endif // defined(C10_SUPPORTS_SIGNAL_HANDLER)
406