From aa63d9f980f95718fc28ca7e222c1e8d7ca9e778 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Tue, 29 Apr 2014 09:35:30 -0700 Subject: [PATCH] Use real time signal for threads instead of SIGURG. This guarantees that any application is not also using this signal for some other purpose. Change-Id: I7c9bbb0ec8bb4e13322ecda951bcd43c6bf6ee1a --- libbacktrace/BacktraceThread.cpp | 6 +++--- libbacktrace/BacktraceThread.h | 9 +++++++++ libbacktrace/backtrace_test.cpp | 13 +++++++++++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/libbacktrace/BacktraceThread.cpp b/libbacktrace/BacktraceThread.cpp index 4cda19ec2..e0bab24a9 100644 --- a/libbacktrace/BacktraceThread.cpp +++ b/libbacktrace/BacktraceThread.cpp @@ -136,7 +136,7 @@ void BacktraceThread::FinishUnwind() { bool BacktraceThread::TriggerUnwindOnThread(ThreadEntry* entry) { entry->state = STATE_WAITING; - if (tgkill(Pid(), Tid(), SIGURG) != 0) { + if (tgkill(Pid(), Tid(), THREAD_SIGNAL) != 0) { BACK_LOGW("tgkill failed %s", strerror(errno)); return false; } @@ -196,9 +196,9 @@ bool BacktraceThread::Unwind(size_t num_ignore_frames) { act.sa_sigaction = SignalHandler; act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; sigemptyset(&act.sa_mask); - if (sigaction(SIGURG, &act, &oldact) == 0) { + if (sigaction(THREAD_SIGNAL, &act, &oldact) == 0) { retval = TriggerUnwindOnThread(entry); - sigaction(SIGURG, &oldact, NULL); + sigaction(THREAD_SIGNAL, &oldact, NULL); } else { BACK_LOGW("sigaction failed %s", strerror(errno)); } diff --git a/libbacktrace/BacktraceThread.h b/libbacktrace/BacktraceThread.h index 3412d5885..9310a4452 100644 --- a/libbacktrace/BacktraceThread.h +++ b/libbacktrace/BacktraceThread.h @@ -18,6 +18,7 @@ #define _LIBBACKTRACE_BACKTRACE_THREAD_H #include +#include #include #include "BacktraceImpl.h" @@ -29,6 +30,14 @@ enum state_e { STATE_CANCEL, }; +// The signal used to cause a thread to dump the stack. +#if defined(__GLIBC__) +// GLIBC reserves __SIGRTMIN signals, so use SIGRTMIN to avoid errors. +#define THREAD_SIGNAL SIGRTMIN +#else +#define THREAD_SIGNAL (__SIGRTMIN+1) +#endif + class BacktraceThreadInterface; struct ThreadEntry { diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp index a5e141b2c..9744922db 100644 --- a/libbacktrace/backtrace_test.cpp +++ b/libbacktrace/backtrace_test.cpp @@ -33,6 +33,9 @@ #include #include +// For the THREAD_SIGNAL definition. +#include "BacktraceThread.h" + #include #include @@ -460,9 +463,15 @@ TEST(libbacktrace, thread_level_trace) { // Wait up to 2 seconds for the tid to be set. ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2)); + // Make sure that the thread signal used is not visible when compiled for + // the target. +#if !defined(__GLIBC__) + ASSERT_LT(THREAD_SIGNAL, SIGRTMIN); +#endif + // Save the current signal action and make sure it is restored afterwards. struct sigaction cur_action; - ASSERT_TRUE(sigaction(SIGURG, NULL, &cur_action) == 0); + ASSERT_TRUE(sigaction(THREAD_SIGNAL, NULL, &cur_action) == 0); UniquePtr backtrace(Backtrace::Create(getpid(), thread_data.tid)); ASSERT_TRUE(backtrace.get() != NULL); @@ -475,7 +484,7 @@ TEST(libbacktrace, thread_level_trace) { // Verify that the old action was restored. struct sigaction new_action; - ASSERT_TRUE(sigaction(SIGURG, NULL, &new_action) == 0); + ASSERT_TRUE(sigaction(THREAD_SIGNAL, NULL, &new_action) == 0); EXPECT_EQ(cur_action.sa_sigaction, new_action.sa_sigaction); EXPECT_EQ(cur_action.sa_flags, new_action.sa_flags); }