BacktraceThread.cpp revision aa63d9f980f95718fc28ca7e222c1e8d7ca9e778
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 <pthread.h>
20#include <signal.h>
21#include <string.h>
22#include <sys/types.h>
23
24#include <cutils/atomic.h>
25
26#include "BacktraceLog.h"
27#include "BacktraceThread.h"
28#include "thread_utils.h"
29
30//-------------------------------------------------------------------------
31// ThreadEntry implementation.
32//-------------------------------------------------------------------------
33static ThreadEntry* g_list = NULL;
34static pthread_mutex_t g_entry_mutex = PTHREAD_MUTEX_INITIALIZER;
35static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER;
36
37ThreadEntry::ThreadEntry(
38    BacktraceThreadInterface* intf, pid_t pid, pid_t tid, size_t num_ignore_frames)
39    : thread_intf(intf), pid(pid), tid(tid), next(NULL), prev(NULL),
40      state(STATE_WAITING), num_ignore_frames(num_ignore_frames) {
41}
42
43ThreadEntry::~ThreadEntry() {
44  pthread_mutex_lock(&g_entry_mutex);
45  if (g_list == this) {
46    g_list = next;
47  } else {
48    if (next) {
49      next->prev = prev;
50    }
51    prev->next = next;
52  }
53  pthread_mutex_unlock(&g_entry_mutex);
54
55  next = NULL;
56  prev = NULL;
57}
58
59ThreadEntry* ThreadEntry::AddThreadToUnwind(
60    BacktraceThreadInterface* intf, pid_t pid, pid_t tid, size_t num_ignore_frames) {
61  ThreadEntry* entry = new ThreadEntry(intf, pid, tid, num_ignore_frames);
62
63  pthread_mutex_lock(&g_entry_mutex);
64  ThreadEntry* cur_entry = g_list;
65  while (cur_entry != NULL) {
66    if (cur_entry->Match(pid, tid)) {
67      // There is already an entry for this pid/tid, this is bad.
68      BACK_LOGW("Entry for pid %d tid %d already exists.", pid, tid);
69
70      pthread_mutex_unlock(&g_entry_mutex);
71      return NULL;
72    }
73    cur_entry = cur_entry->next;
74  }
75
76  // Add the entry to the list.
77  entry->next = g_list;
78  if (g_list) {
79    g_list->prev = entry;
80  }
81  g_list = entry;
82  pthread_mutex_unlock(&g_entry_mutex);
83
84  return entry;
85}
86
87//-------------------------------------------------------------------------
88// BacktraceThread functions.
89//-------------------------------------------------------------------------
90static void SignalHandler(int n __attribute__((unused)), siginfo_t* siginfo,
91                          void* sigcontext) {
92  if (pthread_mutex_lock(&g_entry_mutex) == 0) {
93    pid_t pid = getpid();
94    pid_t tid = gettid();
95    ThreadEntry* cur_entry = g_list;
96    while (cur_entry) {
97      if (cur_entry->Match(pid, tid)) {
98        break;
99      }
100      cur_entry = cur_entry->next;
101    }
102    pthread_mutex_unlock(&g_entry_mutex);
103    if (!cur_entry) {
104      BACK_LOGW("Unable to find pid %d tid %d information", pid, tid);
105      return;
106    }
107
108    if (android_atomic_acquire_cas(STATE_WAITING, STATE_DUMPING, &cur_entry->state) == 0) {
109      cur_entry->thread_intf->ThreadUnwind(siginfo, sigcontext,
110                                           cur_entry->num_ignore_frames);
111    }
112    android_atomic_release_store(STATE_DONE, &cur_entry->state);
113  }
114}
115
116BacktraceThread::BacktraceThread(
117    BacktraceImpl* impl, BacktraceThreadInterface* thread_intf, pid_t tid,
118    BacktraceMap* map)
119    : BacktraceCurrent(impl, map), thread_intf_(thread_intf) {
120  tid_ = tid;
121}
122
123BacktraceThread::~BacktraceThread() {
124}
125
126void BacktraceThread::FinishUnwind() {
127  for (std::vector<backtrace_frame_data_t>::iterator it = frames_.begin();
128       it != frames_.end(); ++it) {
129    it->map = FindMap(it->pc);
130
131    it->func_offset = 0;
132    it->func_name = GetFunctionName(it->pc, &it->func_offset);
133  }
134}
135
136bool BacktraceThread::TriggerUnwindOnThread(ThreadEntry* entry) {
137  entry->state = STATE_WAITING;
138
139  if (tgkill(Pid(), Tid(), THREAD_SIGNAL) != 0) {
140    BACK_LOGW("tgkill failed %s", strerror(errno));
141    return false;
142  }
143
144  // Allow up to ten seconds for the dump to start.
145  int wait_millis = 10000;
146  int32_t state;
147  while (true) {
148    state = android_atomic_acquire_load(&entry->state);
149    if (state != STATE_WAITING) {
150      break;
151    }
152    if (wait_millis--) {
153      usleep(1000);
154    } else {
155      break;
156    }
157  }
158
159  bool cancelled = false;
160  if (state == STATE_WAITING) {
161    if (android_atomic_acquire_cas(state, STATE_CANCEL, &entry->state) == 0) {
162      BACK_LOGW("Cancelled dump of thread %d", entry->tid);
163      state = STATE_CANCEL;
164      cancelled = true;
165    } else {
166      state = android_atomic_acquire_load(&entry->state);
167    }
168  }
169
170  // Wait for at most ten seconds for the cancel or dump to finish.
171  wait_millis = 10000;
172  while (android_atomic_acquire_load(&entry->state) != STATE_DONE) {
173    if (wait_millis--) {
174      usleep(1000);
175    } else {
176      BACK_LOGW("Didn't finish thread unwind in 60 seconds.");
177      break;
178    }
179  }
180  return !cancelled;
181}
182
183bool BacktraceThread::Unwind(size_t num_ignore_frames) {
184  ThreadEntry* entry = ThreadEntry::AddThreadToUnwind(
185      thread_intf_, Pid(), Tid(), num_ignore_frames);
186  if (!entry) {
187    return false;
188  }
189
190  // Prevent multiple threads trying to set the trigger action on different
191  // threads at the same time.
192  bool retval = false;
193  if (pthread_mutex_lock(&g_sigaction_mutex) == 0) {
194    struct sigaction act, oldact;
195    memset(&act, 0, sizeof(act));
196    act.sa_sigaction = SignalHandler;
197    act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
198    sigemptyset(&act.sa_mask);
199    if (sigaction(THREAD_SIGNAL, &act, &oldact) == 0) {
200      retval = TriggerUnwindOnThread(entry);
201      sigaction(THREAD_SIGNAL, &oldact, NULL);
202    } else {
203      BACK_LOGW("sigaction failed %s", strerror(errno));
204    }
205    pthread_mutex_unlock(&g_sigaction_mutex);
206  } else {
207    BACK_LOGW("unable to acquire sigaction mutex.");
208  }
209
210  if (retval) {
211    FinishUnwind();
212  }
213  delete entry;
214
215  return retval;
216}
217