diff options
| -rw-r--r-- | runtime/runtime.cc | 2 | ||||
| -rw-r--r-- | runtime/runtime_linux.cc | 2 | ||||
| -rw-r--r-- | runtime/thread.cc | 8 | ||||
| -rw-r--r-- | runtime/thread.h | 6 | ||||
| -rw-r--r-- | runtime/thread_list.cc | 15 | ||||
| -rw-r--r-- | runtime/utils.cc | 16 | ||||
| -rw-r--r-- | runtime/utils.h | 15 |
7 files changed, 44 insertions, 20 deletions
diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 6c459a3950..556ba56532 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -326,7 +326,7 @@ struct AbortState { if (self == nullptr) { os << "(Aborting thread was not attached to runtime!)\n"; DumpKernelStack(os, GetTid(), " kernel: ", false); - DumpNativeStack(os, GetTid(), " native: ", nullptr); + DumpNativeStack(os, GetTid(), nullptr, " native: ", nullptr); } else { os << "Aborting thread:\n"; if (Locks::mutator_lock_->IsExclusiveHeld(self) || Locks::mutator_lock_->IsSharedHeld(self)) { diff --git a/runtime/runtime_linux.cc b/runtime/runtime_linux.cc index f0b3c4e4cb..122dcb136a 100644 --- a/runtime/runtime_linux.cc +++ b/runtime/runtime_linux.cc @@ -41,7 +41,7 @@ struct Backtrace { public: explicit Backtrace(void* raw_context) : raw_context_(raw_context) {} void Dump(std::ostream& os) const { - DumpNativeStack(os, GetTid(), "\t", nullptr, raw_context_); + DumpNativeStack(os, GetTid(), nullptr, "\t", nullptr, raw_context_); } private: // Stores the context of the signal that was unexpected and will terminate the runtime. The diff --git a/runtime/thread.cc b/runtime/thread.cc index 114e0f6a9c..b0cf418507 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -919,9 +919,9 @@ void Thread::ShortDump(std::ostream& os) const { << "]"; } -void Thread::Dump(std::ostream& os) const { +void Thread::Dump(std::ostream& os, BacktraceMap* backtrace_map) const { DumpState(os); - DumpStack(os); + DumpStack(os, backtrace_map); } mirror::String* Thread::GetThreadName(const ScopedObjectAccessAlreadyRunnable& soa) const { @@ -1480,7 +1480,7 @@ void Thread::DumpJavaStack(std::ostream& os) const { } } -void Thread::DumpStack(std::ostream& os) const { +void Thread::DumpStack(std::ostream& os, BacktraceMap* backtrace_map) const { // TODO: we call this code when dying but may not have suspended the thread ourself. The // IsSuspended check is therefore racy with the use for dumping (normally we inhibit // the race with the thread_suspend_count_lock_). @@ -1496,7 +1496,7 @@ void Thread::DumpStack(std::ostream& os) const { if (dump_for_abort || ShouldShowNativeStack(this)) { DumpKernelStack(os, GetTid(), " kernel: ", false); ArtMethod* method = GetCurrentMethod(nullptr, !dump_for_abort); - DumpNativeStack(os, GetTid(), " native: ", method); + DumpNativeStack(os, GetTid(), backtrace_map, " native: ", method); } DumpJavaStack(os); } else { diff --git a/runtime/thread.h b/runtime/thread.h index 8f3461acdf..138c143d34 100644 --- a/runtime/thread.h +++ b/runtime/thread.h @@ -42,6 +42,8 @@ #include "stack.h" #include "thread_state.h" +class BacktraceMap; + namespace art { namespace gc { @@ -184,7 +186,7 @@ class Thread { void ShortDump(std::ostream& os) const; // Dumps the detailed thread state and the thread stack (used for SIGQUIT). - void Dump(std::ostream& os) const + void Dump(std::ostream& os, BacktraceMap* backtrace_map = nullptr) const REQUIRES(!Locks::thread_suspend_count_lock_) SHARED_REQUIRES(Locks::mutator_lock_); @@ -1042,7 +1044,7 @@ class Thread { void VerifyStackImpl() SHARED_REQUIRES(Locks::mutator_lock_); void DumpState(std::ostream& os) const SHARED_REQUIRES(Locks::mutator_lock_); - void DumpStack(std::ostream& os) const + void DumpStack(std::ostream& os, BacktraceMap* backtrace_map = nullptr) const REQUIRES(!Locks::thread_suspend_count_lock_) SHARED_REQUIRES(Locks::mutator_lock_); diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc index 6176acd9af..bdd5d1099c 100644 --- a/runtime/thread_list.cc +++ b/runtime/thread_list.cc @@ -18,6 +18,7 @@ #define ATRACE_TAG ATRACE_TAG_DALVIK +#include <backtrace/BacktraceMap.h> #include <cutils/trace.h> #include <dirent.h> #include <ScopedLocalRef.h> @@ -109,9 +110,10 @@ pid_t ThreadList::GetLockOwner() { void ThreadList::DumpNativeStacks(std::ostream& os) { MutexLock mu(Thread::Current(), *Locks::thread_list_lock_); + std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(getpid())); for (const auto& thread : list_) { os << "DUMPING THREAD " << thread->GetTid() << "\n"; - DumpNativeStack(os, thread->GetTid(), "\t"); + DumpNativeStack(os, thread->GetTid(), map.get(), "\t"); os << "\n"; } } @@ -138,7 +140,7 @@ static void DumpUnattachedThread(std::ostream& os, pid_t tid) NO_THREAD_SAFETY_A // TODO: Reenable this when the native code in system_server can handle it. // Currently "adb shell kill -3 `pid system_server`" will cause it to exit. if (false) { - DumpNativeStack(os, tid, " native: "); + DumpNativeStack(os, tid, nullptr, " native: "); } os << "\n"; } @@ -175,7 +177,8 @@ static constexpr uint32_t kDumpWaitTimeout = kIsTargetBuild ? 10000 : 20000; // A closure used by Thread::Dump. class DumpCheckpoint FINAL : public Closure { public: - explicit DumpCheckpoint(std::ostream* os) : os_(os), barrier_(0) {} + explicit DumpCheckpoint(std::ostream* os) + : os_(os), barrier_(0), backtrace_map_(BacktraceMap::Create(GetTid())) {} void Run(Thread* thread) OVERRIDE { // Note thread and self may not be equal if thread was already suspended at the point of the @@ -184,7 +187,7 @@ class DumpCheckpoint FINAL : public Closure { std::ostringstream local_os; { ScopedObjectAccess soa(self); - thread->Dump(local_os); + thread->Dump(local_os, backtrace_map_.get()); } local_os << "\n"; { @@ -213,6 +216,8 @@ class DumpCheckpoint FINAL : public Closure { std::ostream* const os_; // The barrier to be passed through and for the requestor to wait upon. Barrier barrier_; + // A backtrace map, so that all threads use a shared info and don't reacquire/parse separately. + std::unique_ptr<BacktraceMap> backtrace_map_; }; void ThreadList::Dump(std::ostream& os) { @@ -1217,7 +1222,7 @@ void ThreadList::Unregister(Thread* self) { std::string thread_name; self->GetThreadName(thread_name); std::ostringstream os; - DumpNativeStack(os, GetTid(), " native: ", nullptr); + DumpNativeStack(os, GetTid(), nullptr, " native: ", nullptr); LOG(ERROR) << "Request to unregister unattached thread " << thread_name << "\n" << os.str(); break; } else { diff --git a/runtime/utils.cc b/runtime/utils.cc index 62af380219..dee4f9c891 100644 --- a/runtime/utils.cc +++ b/runtime/utils.cc @@ -46,7 +46,9 @@ #include <sys/syscall.h> #endif -#include <backtrace/Backtrace.h> // For DumpNativeStack. +// For DumpNativeStack. +#include <backtrace/Backtrace.h> +#include <backtrace/BacktraceMap.h> #if defined(__linux__) #include <linux/unistd.h> @@ -1102,7 +1104,7 @@ static bool PcIsWithinQuickCode(ArtMethod* method, uintptr_t pc) NO_THREAD_SAFET } #endif -void DumpNativeStack(std::ostream& os, pid_t tid, const char* prefix, +void DumpNativeStack(std::ostream& os, pid_t tid, BacktraceMap* existing_map, const char* prefix, ArtMethod* current_method, void* ucontext_ptr) { #if __linux__ // b/18119146 @@ -1110,7 +1112,13 @@ void DumpNativeStack(std::ostream& os, pid_t tid, const char* prefix, return; } - std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, tid)); + BacktraceMap* map = existing_map; + std::unique_ptr<BacktraceMap> tmp_map; + if (map == nullptr) { + tmp_map.reset(BacktraceMap::Create(tid)); + map = tmp_map.get(); + } + std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, tid, map)); if (!backtrace->Unwind(0, reinterpret_cast<ucontext*>(ucontext_ptr))) { os << prefix << "(backtrace::Unwind failed for thread " << tid << ")\n"; return; @@ -1174,7 +1182,7 @@ void DumpNativeStack(std::ostream& os, pid_t tid, const char* prefix, } } #else - UNUSED(os, tid, prefix, current_method, ucontext_ptr); + UNUSED(os, tid, existing_map, prefix, current_method, ucontext_ptr); #endif } diff --git a/runtime/utils.h b/runtime/utils.h index 79502c7971..bd52b686fd 100644 --- a/runtime/utils.h +++ b/runtime/utils.h @@ -31,6 +31,8 @@ #include "globals.h" #include "primitive.h" +class BacktraceMap; + namespace art { class ArtCode; @@ -221,12 +223,19 @@ std::string GetSchedulerGroupName(pid_t tid); void SetThreadName(const char* thread_name); // Dumps the native stack for thread 'tid' to 'os'. -void DumpNativeStack(std::ostream& os, pid_t tid, const char* prefix = "", - ArtMethod* current_method = nullptr, void* ucontext = nullptr) +void DumpNativeStack(std::ostream& os, + pid_t tid, + BacktraceMap* map = nullptr, + const char* prefix = "", + ArtMethod* current_method = nullptr, + void* ucontext = nullptr) NO_THREAD_SAFETY_ANALYSIS; // Dumps the kernel stack for thread 'tid' to 'os'. Note that this is only available on linux-x86. -void DumpKernelStack(std::ostream& os, pid_t tid, const char* prefix = "", bool include_count = true); +void DumpKernelStack(std::ostream& os, + pid_t tid, + const char* prefix = "", + bool include_count = true); // Find $ANDROID_ROOT, /system, or abort. const char* GetAndroidRoot(); |