1
#include <c10/util/Backtrace.h>
2
#include <c10/util/Logging.h>
3
#include <c10/util/signal_handler.h>
5
#if defined(C10_SUPPORTS_SIGNAL_HANDLER)
10
#include <sys/syscall.h>
15
#include <condition_variable>
24
#define SYS_gettid __NR_gettid
27
#define SYS_tgkill __NR_tgkill
33
struct sigaction previousSighup;
34
struct sigaction previousSigint;
35
std::atomic<int> sigintCount(0);
36
std::atomic<int> sighupCount(0);
37
std::atomic<int> hookedUpCount(0);
39
void handleSignal(int signal) {
44
if (previousSighup.sa_handler) {
45
previousSighup.sa_handler(signal);
50
if (previousSigint.sa_handler) {
51
previousSigint.sa_handler(signal);
58
if (hookedUpCount++) {
61
struct sigaction sa {};
63
sa.sa_handler = &handleSignal;
65
sa.sa_flags = SA_RESTART;
67
sigfillset(&sa.sa_mask);
69
if (sigaction(SIGHUP, &sa, &previousSighup) == -1) {
70
LOG(FATAL) << "Cannot install SIGHUP handler.";
72
if (sigaction(SIGINT, &sa, &previousSigint) == -1) {
73
LOG(FATAL) << "Cannot install SIGINT handler.";
79
if (--hookedUpCount > 0) {
82
struct sigaction sa {};
84
sa.sa_handler = SIG_DFL;
86
sa.sa_flags = SA_RESTART;
88
sigfillset(&sa.sa_mask);
90
if (sigaction(SIGHUP, &previousSighup, nullptr) == -1) {
91
LOG(FATAL) << "Cannot uninstall SIGHUP handler.";
93
if (sigaction(SIGINT, &previousSigint, nullptr) == -1) {
94
LOG(FATAL) << "Cannot uninstall SIGINT handler.";
102
#if defined(C10_SUPPORTS_FATAL_SIGNAL_HANDLERS)
104
FatalSignalHandler& FatalSignalHandler::getInstance() {
106
static FatalSignalHandler* handler = new FatalSignalHandler();
110
FatalSignalHandler::~FatalSignalHandler() = default;
112
FatalSignalHandler::FatalSignalHandler()
113
: fatalSignalHandlersInstalled(false),
114
fatalSignalReceived(false),
115
fatalSignalName("<UNKNOWN>"),
118
signalReceived(false) {}
121
FatalSignalHandler::signal_handler FatalSignalHandler::kSignalHandlers[] = {
122
{"SIGABRT", SIGABRT, {}},
123
{"SIGINT", SIGINT, {}},
124
{"SIGILL", SIGILL, {}},
125
{"SIGFPE", SIGFPE, {}},
126
{"SIGBUS", SIGBUS, {}},
127
{"SIGSEGV", SIGSEGV, {}},
130
struct sigaction* FatalSignalHandler::getPreviousSigaction(int signum) {
131
for (auto handler = kSignalHandlers; handler->name != nullptr; handler++) {
132
if (handler->signum == signum) {
133
return &handler->previous;
139
const char* FatalSignalHandler::getSignalName(int signum) {
140
for (auto handler = kSignalHandlers; handler->name != nullptr; handler++) {
141
if (handler->signum == signum) {
142
return handler->name;
148
void FatalSignalHandler::callPreviousSignalHandler(
149
struct sigaction* action,
153
if (!action->sa_handler) {
156
if ((action->sa_flags & SA_SIGINFO) == SA_SIGINFO) {
157
action->sa_sigaction(signum, info, ctx);
159
action->sa_handler(signum);
164
void FatalSignalHandler::stacktraceSignalHandler(bool needsLock) {
165
std::unique_lock<std::mutex> ul(writingMutex, std::defer_lock);
168
signalReceived = true;
170
pid_t tid = static_cast<pid_t>(syscall(SYS_gettid));
171
std::string backtrace = fmt::format(
172
"{}({}), PID: {}, Thread {}: \n {}",
177
c10::get_backtrace());
178
std::cerr << backtrace << std::endl;
181
writingCond.notify_all();
185
void FatalSignalHandler::fatalSignalHandlerPostProcess() {}
187
void FatalSignalHandler::fatalSignalHandlerStatic(int signum) {
188
getInstance().fatalSignalHandler(signum);
192
void FatalSignalHandler::fatalSignalHandler(int signum) {
194
const char* name = getSignalName(signum);
198
if (fatalSignalReceived) {
203
fatalSignalReceived = true;
205
fatalSignum = signum;
206
fatalSignalName = name;
209
DIR* procDir = opendir("/proc/self/task");
211
pid_t pid = getpid();
212
pid_t currentTid = static_cast<pid_t>(syscall(SYS_gettid));
213
struct dirent* entry = nullptr;
214
std::unique_lock<std::mutex> ul(writingMutex);
215
while ((entry = readdir(procDir)) != nullptr) {
216
if (entry->d_name[0] == '.') {
219
pid_t tid = atoi(entry->d_name);
222
if (tid != currentTid) {
223
signalReceived = false;
224
syscall(SYS_tgkill, pid, tid, SIGUSR2);
225
auto now = std::chrono::system_clock::now();
226
using namespace std::chrono_literals;
229
if (std::cv_status::timeout == writingCond.wait_until(ul, now + 2s)) {
230
if (!signalReceived) {
231
std::cerr << "signal lost waiting for stacktrace " << pid << ":"
237
stacktraceSignalHandler(false);
241
perror("Failed to open /proc/self/task");
243
fatalSignalHandlerPostProcess();
244
sigaction(signum, getPreviousSigaction(signum), nullptr);
249
void FatalSignalHandler::stacktraceSignalHandlerStatic(
253
getInstance().stacktraceSignalHandler(signum, info, ctx);
256
void FatalSignalHandler::stacktraceSignalHandler(
260
if (fatalSignalReceived) {
261
stacktraceSignalHandler(true);
265
callPreviousSignalHandler(&previousSigusr2, signum, info, ctx);
274
void FatalSignalHandler::installFatalSignalHandlers() {
275
std::lock_guard<std::mutex> locker(fatalSignalHandlersInstallationMutex);
276
if (fatalSignalHandlersInstalled) {
279
fatalSignalHandlersInstalled = true;
280
struct sigaction sa {};
281
sigemptyset(&sa.sa_mask);
284
sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
285
sa.sa_handler = FatalSignalHandler::fatalSignalHandlerStatic;
286
for (auto* handler = kSignalHandlers; handler->name != nullptr; handler++) {
287
if (sigaction(handler->signum, &sa, &handler->previous)) {
288
std::string str("Failed to add ");
289
str += handler->name;
294
sa.sa_sigaction = FatalSignalHandler::stacktraceSignalHandlerStatic;
295
if (sigaction(SIGUSR2, &sa, &previousSigusr2)) {
296
perror("Failed to add SIGUSR2 handler!");
300
void FatalSignalHandler::uninstallFatalSignalHandlers() {
301
std::lock_guard<std::mutex> locker(fatalSignalHandlersInstallationMutex);
302
if (!fatalSignalHandlersInstalled) {
305
fatalSignalHandlersInstalled = false;
306
for (auto* handler = kSignalHandlers; handler->name != nullptr; handler++) {
307
if (sigaction(handler->signum, &handler->previous, nullptr)) {
308
std::string str("Failed to remove ");
309
str += handler->name;
313
handler->previous = {};
316
if (sigaction(SIGUSR2, &previousSigusr2, nullptr)) {
317
perror("Failed to add SIGUSR2 handler!");
319
previousSigusr2 = {};
324
SignalHandler::SignalHandler(
325
SignalHandler::Action SIGINT_action,
326
SignalHandler::Action SIGHUP_action)
327
: SIGINT_action_(SIGINT_action),
328
SIGHUP_action_(SIGHUP_action),
329
my_sigint_count_(sigintCount),
330
my_sighup_count_(sighupCount) {
334
SignalHandler::~SignalHandler() {
340
bool SignalHandler::GotSIGINT() {
341
uint64_t count = sigintCount;
342
uint64_t localCount = my_sigint_count_.exchange(count);
343
return (localCount != count);
348
bool SignalHandler::GotSIGHUP() {
349
uint64_t count = sighupCount;
350
uint64_t localCount = my_sighup_count_.exchange(count);
351
return (localCount != count);
354
SignalHandler::Action SignalHandler::CheckForSignals() {
356
return SIGHUP_action_;
359
return SIGINT_action_;
361
return SignalHandler::Action::NONE;
364
#if defined(C10_SUPPORTS_FATAL_SIGNAL_HANDLERS)
365
void FatalSignalHandler::setPrintStackTracesOnFatalSignal(bool print) {
367
installFatalSignalHandlers();
369
uninstallFatalSignalHandlers();
372
bool FatalSignalHandler::printStackTracesOnFatalSignal() {
373
std::lock_guard<std::mutex> locker(fatalSignalHandlersInstallationMutex);
374
return fatalSignalHandlersInstalled;
385
SignalHandler::SignalHandler(
386
SignalHandler::Action SIGINT_action,
387
SignalHandler::Action SIGHUP_action) {
388
SIGINT_action_ = SIGINT_action;
389
SIGHUP_action_ = SIGHUP_action;
390
my_sigint_count_ = 0;
391
my_sighup_count_ = 0;
393
SignalHandler::~SignalHandler() {}
394
bool SignalHandler::GotSIGINT() {
397
bool SignalHandler::GotSIGHUP() {
400
SignalHandler::Action SignalHandler::CheckForSignals() {
401
return SignalHandler::Action::NONE;