diff options
Diffstat (limited to 'libbacktrace/BacktraceThread.cpp')
-rw-r--r-- | libbacktrace/BacktraceThread.cpp | 106 |
1 files changed, 55 insertions, 51 deletions
diff --git a/libbacktrace/BacktraceThread.cpp b/libbacktrace/BacktraceThread.cpp index 6c3641e..8e664c4 100644 --- a/libbacktrace/BacktraceThread.cpp +++ b/libbacktrace/BacktraceThread.cpp @@ -31,55 +31,55 @@ // ThreadEntry implementation. //------------------------------------------------------------------------- static ThreadEntry* g_list = NULL; -static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t g_entry_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER; ThreadEntry::ThreadEntry( BacktraceThreadInterface* intf, pid_t pid, pid_t tid, size_t num_ignore_frames) - : thread_intf_(intf), pid_(pid), tid_(tid), next_(NULL), prev_(NULL), - state_(STATE_WAITING), num_ignore_frames_(num_ignore_frames) { + : thread_intf(intf), pid(pid), tid(tid), next(NULL), prev(NULL), + state(STATE_WAITING), num_ignore_frames(num_ignore_frames) { } ThreadEntry::~ThreadEntry() { - pthread_mutex_lock(&g_mutex); + pthread_mutex_lock(&g_entry_mutex); if (g_list == this) { - g_list = next_; + g_list = next; } else { - if (next_) { - next_->prev_ = prev_; + if (next) { + next->prev = prev; } - prev_->next_ = next_; + prev->next = next; } - pthread_mutex_unlock(&g_mutex); + pthread_mutex_unlock(&g_entry_mutex); - next_ = NULL; - prev_ = NULL; + next = NULL; + prev = NULL; } ThreadEntry* ThreadEntry::AddThreadToUnwind( BacktraceThreadInterface* intf, pid_t pid, pid_t tid, size_t num_ignore_frames) { ThreadEntry* entry = new ThreadEntry(intf, pid, tid, num_ignore_frames); - pthread_mutex_lock(&g_mutex); + pthread_mutex_lock(&g_entry_mutex); ThreadEntry* cur_entry = g_list; while (cur_entry != NULL) { if (cur_entry->Match(pid, tid)) { // There is already an entry for this pid/tid, this is bad. - ALOGW("%s::%s(): Entry for pid %d tid %d already exists.\n", - __FILE__, __FUNCTION__, pid, tid); + BACK_LOGW("Entry for pid %d tid %d already exists.", pid, tid); - pthread_mutex_unlock(&g_mutex); + pthread_mutex_unlock(&g_entry_mutex); return NULL; } - cur_entry = cur_entry->next_; + cur_entry = cur_entry->next; } // Add the entry to the list. - entry->next_ = g_list; + entry->next = g_list; if (g_list) { - g_list->prev_ = entry; + g_list->prev = entry; } g_list = entry; - pthread_mutex_unlock(&g_mutex); + pthread_mutex_unlock(&g_entry_mutex); return entry; } @@ -89,7 +89,7 @@ ThreadEntry* ThreadEntry::AddThreadToUnwind( //------------------------------------------------------------------------- static void SignalHandler(int n __attribute__((unused)), siginfo_t* siginfo, void* sigcontext) { - if (pthread_mutex_lock(&g_mutex) == 0) { + if (pthread_mutex_lock(&g_entry_mutex) == 0) { pid_t pid = getpid(); pid_t tid = gettid(); ThreadEntry* cur_entry = g_list; @@ -97,20 +97,19 @@ static void SignalHandler(int n __attribute__((unused)), siginfo_t* siginfo, if (cur_entry->Match(pid, tid)) { break; } - cur_entry = cur_entry->next_; + cur_entry = cur_entry->next; } - pthread_mutex_unlock(&g_mutex); + pthread_mutex_unlock(&g_entry_mutex); if (!cur_entry) { - ALOGW("%s::%s(): Unable to find pid %d tid %d information\n", - __FILE__, __FUNCTION__, pid, tid); + BACK_LOGW("Unable to find pid %d tid %d information", pid, tid); return; } - if (android_atomic_acquire_cas(STATE_WAITING, STATE_DUMPING, &cur_entry->state_) == 0) { - cur_entry->thread_intf_->ThreadUnwind(siginfo, sigcontext, - cur_entry->num_ignore_frames_); + if (android_atomic_acquire_cas(STATE_WAITING, STATE_DUMPING, &cur_entry->state) == 0) { + cur_entry->thread_intf->ThreadUnwind(siginfo, sigcontext, + cur_entry->num_ignore_frames); } - android_atomic_release_store(STATE_DONE, &cur_entry->state_); + android_atomic_release_store(STATE_DONE, &cur_entry->state); } } @@ -143,18 +142,18 @@ void BacktraceThread::FinishUnwind() { } bool BacktraceThread::TriggerUnwindOnThread(ThreadEntry* entry) { - entry->state_ = STATE_WAITING; + entry->state = STATE_WAITING; if (tgkill(Pid(), Tid(), SIGURG) != 0) { - ALOGW("%s::%s(): tgkill failed %s\n", __FILE__, __FUNCTION__, strerror(errno)); + BACK_LOGW("tgkill failed %s", strerror(errno)); return false; } - // Allow up to a second for the dump to occur. - int wait_millis = 1000; + // Allow up to ten seconds for the dump to start. + int wait_millis = 10000; int32_t state; while (true) { - state = android_atomic_acquire_load(&entry->state_); + state = android_atomic_acquire_load(&entry->state); if (state != STATE_WAITING) { break; } @@ -167,24 +166,22 @@ bool BacktraceThread::TriggerUnwindOnThread(ThreadEntry* entry) { bool cancelled = false; if (state == STATE_WAITING) { - if (android_atomic_acquire_cas(state, STATE_CANCEL, &entry->state_) == 0) { - ALOGW("%s::%s(): Cancelled dump of thread %d\n", __FILE__, __FUNCTION__, - entry->tid_); + if (android_atomic_acquire_cas(state, STATE_CANCEL, &entry->state) == 0) { + BACK_LOGW("Cancelled dump of thread %d", entry->tid); state = STATE_CANCEL; cancelled = true; } else { - state = android_atomic_acquire_load(&entry->state_); + state = android_atomic_acquire_load(&entry->state); } } - // Wait for at most one minute for the dump to finish. - wait_millis = 60000; - while (android_atomic_acquire_load(&entry->state_) != STATE_DONE) { + // Wait for at most ten seconds for the cancel or dump to finish. + wait_millis = 10000; + while (android_atomic_acquire_load(&entry->state) != STATE_DONE) { if (wait_millis--) { usleep(1000); } else { - ALOGW("%s::%s(): Didn't finish thread unwind in 60 seconds.\n", - __FILE__, __FUNCTION__); + BACK_LOGW("Didn't finish thread unwind in 60 seconds."); break; } } @@ -202,17 +199,24 @@ bool BacktraceThread::Unwind(size_t num_ignore_frames) { return false; } + // Prevent multiple threads trying to set the trigger action on different + // threads at the same time. bool retval = false; - struct sigaction act, oldact; - memset(&act, 0, sizeof(act)); - act.sa_sigaction = SignalHandler; - act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; - sigemptyset(&act.sa_mask); - if (sigaction(SIGURG, &act, &oldact) == 0) { - retval = TriggerUnwindOnThread(entry); - sigaction(SIGURG, &oldact, NULL); + if (pthread_mutex_lock(&g_sigaction_mutex) == 0) { + struct sigaction act, oldact; + memset(&act, 0, sizeof(act)); + act.sa_sigaction = SignalHandler; + act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; + sigemptyset(&act.sa_mask); + if (sigaction(SIGURG, &act, &oldact) == 0) { + retval = TriggerUnwindOnThread(entry); + sigaction(SIGURG, &oldact, NULL); + } else { + BACK_LOGW("sigaction failed %s", strerror(errno)); + } + pthread_mutex_unlock(&g_sigaction_mutex); } else { - ALOGW("%s::%s(): sigaction failed %s\n", __FILE__, __FUNCTION__, strerror(errno)); + BACK_LOGW("unable to acquire sigaction mutex."); } if (retval) { |