BacktraceThread.cpp revision db44538387b08f367fc2419653639866f4c2fbd6
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <errno.h> 18#include <inttypes.h> 19#include <limits.h> 20#include <pthread.h> 21#include <signal.h> 22#include <stdlib.h> 23#include <string.h> 24#include <sys/syscall.h> 25#include <sys/time.h> 26#include <sys/types.h> 27#include <ucontext.h> 28#include <unistd.h> 29 30#include <cutils/atomic.h> 31 32#include "BacktraceLog.h" 33#include "BacktraceThread.h" 34#include "thread_utils.h" 35 36//------------------------------------------------------------------------- 37// ThreadEntry implementation. 38//------------------------------------------------------------------------- 39ThreadEntry* ThreadEntry::list_ = NULL; 40pthread_mutex_t ThreadEntry::list_mutex_ = PTHREAD_MUTEX_INITIALIZER; 41 42// Assumes that ThreadEntry::list_mutex_ has already been locked before 43// creating a ThreadEntry object. 44ThreadEntry::ThreadEntry(pid_t pid, pid_t tid) 45 : pid_(pid), tid_(tid), ref_count_(1), mutex_(PTHREAD_MUTEX_INITIALIZER), 46 wait_mutex_(PTHREAD_MUTEX_INITIALIZER), wait_value_(0), 47 next_(ThreadEntry::list_), prev_(NULL) { 48 pthread_condattr_t attr; 49 pthread_condattr_init(&attr); 50 pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); 51 pthread_cond_init(&wait_cond_, &attr); 52 53 // Add ourselves to the list. 54 if (ThreadEntry::list_) { 55 ThreadEntry::list_->prev_ = this; 56 } 57 ThreadEntry::list_ = this; 58} 59 60ThreadEntry* ThreadEntry::Get(pid_t pid, pid_t tid, bool create) { 61 pthread_mutex_lock(&ThreadEntry::list_mutex_); 62 ThreadEntry* entry = list_; 63 while (entry != NULL) { 64 if (entry->Match(pid, tid)) { 65 break; 66 } 67 entry = entry->next_; 68 } 69 70 if (!entry) { 71 if (create) { 72 entry = new ThreadEntry(pid, tid); 73 } 74 } else { 75 entry->ref_count_++; 76 } 77 pthread_mutex_unlock(&ThreadEntry::list_mutex_); 78 79 return entry; 80} 81 82void ThreadEntry::Remove(ThreadEntry* entry) { 83 pthread_mutex_unlock(&entry->mutex_); 84 85 pthread_mutex_lock(&ThreadEntry::list_mutex_); 86 if (--entry->ref_count_ == 0) { 87 delete entry; 88 } 89 pthread_mutex_unlock(&ThreadEntry::list_mutex_); 90} 91 92// Assumes that ThreadEntry::list_mutex_ has already been locked before 93// deleting a ThreadEntry object. 94ThreadEntry::~ThreadEntry() { 95 if (list_ == this) { 96 list_ = next_; 97 } else { 98 if (next_) { 99 next_->prev_ = prev_; 100 } 101 prev_->next_ = next_; 102 } 103 104 next_ = NULL; 105 prev_ = NULL; 106 107 pthread_cond_destroy(&wait_cond_); 108} 109 110void ThreadEntry::Wait(int value) { 111 timespec ts; 112 if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) { 113 BACK_LOGW("clock_gettime failed: %s", strerror(errno)); 114 abort(); 115 } 116 ts.tv_sec += 10; 117 118 pthread_mutex_lock(&wait_mutex_); 119 while (wait_value_ != value) { 120 int ret = pthread_cond_timedwait(&wait_cond_, &wait_mutex_, &ts); 121 if (ret != 0) { 122 BACK_LOGW("pthread_cond_timedwait failed: %s", strerror(ret)); 123 break; 124 } 125 } 126 pthread_mutex_unlock(&wait_mutex_); 127} 128 129void ThreadEntry::Wake() { 130 pthread_mutex_lock(&wait_mutex_); 131 wait_value_++; 132 pthread_mutex_unlock(&wait_mutex_); 133 134 pthread_cond_signal(&wait_cond_); 135} 136 137void ThreadEntry::CopyUcontextFromSigcontext(void* sigcontext) { 138 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(sigcontext); 139 // The only thing the unwinder cares about is the mcontext data. 140 memcpy(&ucontext_.uc_mcontext, &ucontext->uc_mcontext, sizeof(ucontext->uc_mcontext)); 141} 142 143//------------------------------------------------------------------------- 144// BacktraceThread functions. 145//------------------------------------------------------------------------- 146static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER; 147 148static void SignalHandler(int, siginfo_t*, void* sigcontext) { 149 ThreadEntry* entry = ThreadEntry::Get(getpid(), gettid(), false); 150 if (!entry) { 151 BACK_LOGW("Unable to find pid %d tid %d information", getpid(), gettid()); 152 return; 153 } 154 155 entry->CopyUcontextFromSigcontext(sigcontext); 156 157 // Indicate the ucontext is now valid. 158 entry->Wake(); 159 160 // Pause the thread until the unwind is complete. This avoids having 161 // the thread run ahead causing problems. 162 entry->Wait(2); 163 164 ThreadEntry::Remove(entry); 165} 166 167BacktraceThread::BacktraceThread(BacktraceImpl* impl, pid_t tid, BacktraceMap* map) 168 : BacktraceCurrent(impl, map) { 169 tid_ = tid; 170} 171 172BacktraceThread::~BacktraceThread() { 173} 174 175bool BacktraceThread::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { 176 if (ucontext) { 177 // Unwind using an already existing ucontext. 178 return impl_->Unwind(num_ignore_frames, ucontext); 179 } 180 181 // Prevent multiple threads trying to set the trigger action on different 182 // threads at the same time. 183 if (pthread_mutex_lock(&g_sigaction_mutex) < 0) { 184 BACK_LOGW("sigaction failed: %s", strerror(errno)); 185 return false; 186 } 187 188 ThreadEntry* entry = ThreadEntry::Get(Pid(), Tid()); 189 entry->Lock(); 190 191 struct sigaction act, oldact; 192 memset(&act, 0, sizeof(act)); 193 act.sa_sigaction = SignalHandler; 194 act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; 195 sigemptyset(&act.sa_mask); 196 if (sigaction(THREAD_SIGNAL, &act, &oldact) != 0) { 197 BACK_LOGW("sigaction failed %s", strerror(errno)); 198 entry->Unlock(); 199 ThreadEntry::Remove(entry); 200 pthread_mutex_unlock(&g_sigaction_mutex); 201 return false; 202 } 203 204 if (tgkill(Pid(), Tid(), THREAD_SIGNAL) != 0) { 205 BACK_LOGW("tgkill %d failed: %s", Tid(), strerror(errno)); 206 sigaction(THREAD_SIGNAL, &oldact, NULL); 207 entry->Unlock(); 208 ThreadEntry::Remove(entry); 209 pthread_mutex_unlock(&g_sigaction_mutex); 210 return false; 211 } 212 213 // Wait for the thread to get the ucontext. 214 entry->Wait(1); 215 216 // After the thread has received the signal, allow other unwinders to 217 // continue. 218 sigaction(THREAD_SIGNAL, &oldact, NULL); 219 pthread_mutex_unlock(&g_sigaction_mutex); 220 221 bool unwind_done = impl_->Unwind(num_ignore_frames, entry->GetUcontext()); 222 223 // Tell the signal handler to exit and release the entry. 224 entry->Wake(); 225 226 return unwind_done; 227} 228