diff options
| author | 2012-06-05 17:42:23 -0700 | |
|---|---|---|
| committer | 2012-06-05 17:42:23 -0700 | |
| commit | abbe07d095547ded03c2e9d0d53943d43471278d (patch) | |
| tree | f63555369a0e40574ee30ff634904e5eb3a467b5 /src | |
| parent | 2ab7f486ba73b2846bdbdde65cc2d41f62a26015 (diff) | |
Include non-attached native threads in the SIGQUIT output.
These threads look something like this:
"droid.phasebeam' prio=5 tid=? (not attached)
| sysTid=5369 nice=-4 sched=0/0 cgrp=default
| schedstat=( 0 0 0 ) utm=1 stm=8 core=0 HZ=100
native: __futex_syscall3+8 [0x40074678] (libc.so)
native: __pthread_cond_timedwait_relative+48 [0x40079474] (libc.so)
native: __pthread_cond_timedwait+72 [0x40079528] (libc.so)
native: android::renderscript::Signal::wait(unsigned long long)+58 [0x418bf117] (libRS.so)
native: android::renderscript::LocklessCommandFifo::wait(unsigned long long)+38 [0x418bab97] (libRS.so)
native: android::renderscript::LocklessCommandFifo::get(unsigned int*, unsigned int*, unsigned long long)+22 [0x418babbb] (libRS.so)
native: android::renderscript::ThreadIO::playCoreCommands(android::renderscript::Context*, bool, unsigned long long)+126 [0x418bf84b] (libRS.so)
native: android::renderscript::Context::threadProc(void*)+382 [0x418b7347] (libRS.so)
native: __thread_entry+48 [0x40079d30] (libc.so)
native: pthread_create+180 [0x40079884] (libc.so)
Also fix running tests on Mac OS, which has no /proc/self/cmdline.
Change-Id: Ib5e6f7e23dd45aecdf814e84f573361a5d91bac6
Diffstat (limited to 'src')
| -rw-r--r-- | src/signal_catcher.cc | 10 | ||||
| -rw-r--r-- | src/thread.cc | 76 | ||||
| -rw-r--r-- | src/thread.h | 4 | ||||
| -rw-r--r-- | src/thread_list.cc | 38 | ||||
| -rw-r--r-- | src/thread_list.h | 3 |
5 files changed, 104 insertions, 27 deletions
diff --git a/src/signal_catcher.cc b/src/signal_catcher.cc index 0703b6105d..33600ba18d 100644 --- a/src/signal_catcher.cc +++ b/src/signal_catcher.cc @@ -36,8 +36,13 @@ #include "thread_list.h" #include "utils.h" +#if !defined(__APPLE__) +#define HAVE_PROC_CMDLINE +#endif + namespace art { +#if defined(HAVE_PROC_CMDLINE) static bool ReadCmdLine(std::string& result) { if (!ReadFileToString("/proc/self/cmdline", &result)) { return false; @@ -45,6 +50,7 @@ static bool ReadCmdLine(std::string& result) { std::replace(result.begin(), result.end(), '\0', ' '); return true; } +#endif SignalCatcher::SignalCatcher(const std::string& stack_trace_file) : stack_trace_file_(stack_trace_file), @@ -53,9 +59,11 @@ SignalCatcher::SignalCatcher(const std::string& stack_trace_file) thread_(NULL) { SetHaltFlag(false); +#if defined(HAVE_PROC_CMDLINE) // Stash the original command line for SIGQUIT reporting. // By then, /proc/self/cmdline will have been rewritten to something like "system_server". CHECK(ReadCmdLine(cmd_line_)); +#endif // Create a raw pthread; its start routine will attach to the runtime. CHECK_PTHREAD_CALL(pthread_create, (&pthread_, NULL, &Run, this), "signal catcher thread"); @@ -121,6 +129,7 @@ void SignalCatcher::HandleSigQuit() { os << "\n" << "----- pid " << getpid() << " at " << GetIsoDate() << " -----\n"; +#if defined(HAVE_PROC_CMDLINE) std::string current_cmd_line; if (ReadCmdLine(current_cmd_line) && current_cmd_line != cmd_line_) { os << "Cmdline: " << current_cmd_line; @@ -130,6 +139,7 @@ void SignalCatcher::HandleSigQuit() { if (current_cmd_line != cmd_line_) { os << "Original command line: " << cmd_line_ << "\n"; } +#endif os << "Build type: " << (kIsDebugBuild ? "debug" : "optimized") << "\n"; diff --git a/src/thread.cc b/src/thread.cc index 51b8e31661..d854c3ba88 100644 --- a/src/thread.cc +++ b/src/thread.cc @@ -438,16 +438,16 @@ void Thread::GetThreadName(std::string& name) const { name.assign(*name_); } -void Thread::DumpState(std::ostream& os) const { +void Thread::DumpState(std::ostream& os, const Thread* thread, pid_t tid) { std::string group_name; int priority; bool is_daemon = false; - if (peer_ != NULL) { - priority = DecodeField(WellKnownClasses::java_lang_Thread_priority)->GetInt(peer_); - is_daemon = DecodeField(WellKnownClasses::java_lang_Thread_daemon)->GetBoolean(peer_); + if (thread != NULL && thread->peer_ != NULL) { + priority = DecodeField(WellKnownClasses::java_lang_Thread_priority)->GetInt(thread->peer_); + is_daemon = DecodeField(WellKnownClasses::java_lang_Thread_daemon)->GetBoolean(thread->peer_); - Object* thread_group = GetThreadGroup(); + Object* thread_group = thread->GetThreadGroup(); if (thread_group != NULL) { Field* group_name_field = DecodeField(WellKnownClasses::java_lang_ThreadGroup_name); String* group_name_string = reinterpret_cast<String*>(group_name_field->GetObject(thread_group)); @@ -461,33 +461,49 @@ void Thread::DumpState(std::ostream& os) const { sched_param sp; CHECK_PTHREAD_CALL(pthread_getschedparam, (pthread_self(), &policy, &sp), __FUNCTION__); - std::string scheduler_group_name(GetSchedulerGroupName(GetTid())); + std::string scheduler_group_name(GetSchedulerGroupName(tid)); if (scheduler_group_name.empty()) { scheduler_group_name = "default"; } - os << '"' << *name_ << '"'; - if (is_daemon) { - os << " daemon"; + if (thread != NULL) { + os << '"' << *thread->name_ << '"'; + if (is_daemon) { + os << " daemon"; + } + os << " prio=" << priority + << " tid=" << thread->GetThinLockId() + << " " << thread->GetState() << "\n"; + } else { + std::string thread_name; + if (ReadFileToString(StringPrintf("/proc/self/task/%d/comm", tid), &thread_name)) { + thread_name.resize(thread_name.size() - 1); // Lose the trailing '\n'. + } else { + thread_name = "<unknown>"; + } + os << '"' << thread_name << '"' + << " prio=" << priority + << " tid=?" + << " (not attached)\n"; } - os << " prio=" << priority - << " tid=" << GetThinLockId() - << " " << GetState() << "\n"; - os << " | group=\"" << group_name << "\"" - << " sCount=" << suspend_count_ - << " dsCount=" << debug_suspend_count_ - << " obj=" << reinterpret_cast<void*>(peer_) - << " self=" << reinterpret_cast<const void*>(this) << "\n"; - os << " | sysTid=" << GetTid() - << " nice=" << getpriority(PRIO_PROCESS, GetTid()) + if (thread != NULL) { + os << " | group=\"" << group_name << "\"" + << " sCount=" << thread->suspend_count_ + << " dsCount=" << thread->debug_suspend_count_ + << " obj=" << reinterpret_cast<void*>(thread->peer_) + << " self=" << reinterpret_cast<const void*>(thread) << "\n"; + } + os << " | sysTid=" << tid + << " nice=" << getpriority(PRIO_PROCESS, tid) << " sched=" << policy << "/" << sp.sched_priority - << " cgrp=" << scheduler_group_name - << " handle=" << pthread_self() << "\n"; + << " cgrp=" << scheduler_group_name << "\n"; + + // TODO: fix this; it's never worked in art! << " handle=" << pthread_self() << "\n"; // Grab the scheduler stats for this thread. std::string scheduler_stats; - if (ReadFileToString(StringPrintf("/proc/self/task/%d/schedstat", GetTid()), &scheduler_stats)) { + if (ReadFileToString(StringPrintf("/proc/self/task/%d/schedstat", tid), &scheduler_stats)) { scheduler_stats.resize(scheduler_stats.size() - 1); // Lose the trailing '\n'. } else { scheduler_stats = "0 0 0"; @@ -496,15 +512,21 @@ void Thread::DumpState(std::ostream& os) const { int utime = 0; int stime = 0; int task_cpu = 0; - GetTaskStats(GetTid(), utime, stime, task_cpu); + GetTaskStats(tid, utime, stime, task_cpu); os << " | schedstat=( " << scheduler_stats << " )" << " utm=" << utime << " stm=" << stime - << " core=" << task_cpu; - os << " HZ=" << sysconf(_SC_CLK_TCK) << "\n" - << " | stack=" << reinterpret_cast<void*>(stack_begin_) << "-" << reinterpret_cast<void*>(stack_end_) - << " stackSize=" << PrettySize(stack_size_) << "\n"; + << " core=" << task_cpu + << " HZ=" << sysconf(_SC_CLK_TCK) << "\n"; + if (thread != NULL) { + os << " | stack=" << reinterpret_cast<void*>(thread->stack_begin_) << "-" << reinterpret_cast<void*>(thread->stack_end_) + << " stackSize=" << PrettySize(thread->stack_size_) << "\n"; + } +} + +void Thread::DumpState(std::ostream& os) const { + Thread::DumpState(os, this, GetTid()); } #if !defined(ART_USE_LLVM_COMPILER) diff --git a/src/thread.h b/src/thread.h index f51b581db5..7d885c0e8a 100644 --- a/src/thread.h +++ b/src/thread.h @@ -129,6 +129,10 @@ class PACKED Thread { // When full == false, dumps a one-line summary of thread state (used for operator<<). void Dump(std::ostream& os, bool full = true) const; + // Dumps the SIGQUIT per-thread header. 'thread' can be NULL for a non-attached thread, in which + // case we use 'tid' to identify the thread, and we'll include as much information as we can. + static void DumpState(std::ostream& os, const Thread* thread, pid_t tid); + ThreadState GetState() const { return state_; } diff --git a/src/thread_list.cc b/src/thread_list.cc index e8b412c291..3d0e0be4cd 100644 --- a/src/thread_list.cc +++ b/src/thread_list.cc @@ -16,11 +16,14 @@ #include "thread_list.h" +#include <dirent.h> +#include <sys/types.h> #include <unistd.h> #include "debugger.h" #include "scoped_heap_lock.h" #include "scoped_thread_list_lock.h" +#include "utils.h" namespace art { @@ -50,6 +53,15 @@ bool ThreadList::Contains(Thread* thread) { return find(list_.begin(), list_.end(), thread) != list_.end(); } +bool ThreadList::Contains(pid_t tid) { + for (It it = list_.begin(), end = list_.end(); it != end; ++it) { + if ((*it)->tid_ == tid) { + return true; + } + } + return false; +} + pid_t ThreadList::GetLockOwner() { return thread_list_lock_.GetOwner(); } @@ -57,6 +69,32 @@ pid_t ThreadList::GetLockOwner() { void ThreadList::DumpForSigQuit(std::ostream& os) { ScopedThreadListLock thread_list_lock; DumpLocked(os); + DumpUnattachedThreads(os); +} + +static void DumpUnattachedThread(std::ostream& os, pid_t tid) { + Thread::DumpState(os, NULL, tid); + DumpKernelStack(os, tid, " kernel: ", false); + DumpNativeStack(os, tid, " native: ", false); + os << "\n"; +} + +void ThreadList::DumpUnattachedThreads(std::ostream& os) { + DIR* d = opendir("/proc/self/task"); + if (!d) { + return; + } + + dirent de; + dirent* result; + while (!readdir_r(d, &de, &result) && result != NULL) { + char* end; + pid_t tid = strtol(de.d_name, &end, 10); + if (!*end && !Contains(tid)) { + DumpUnattachedThread(os, tid); + } + } + closedir(d); } void ThreadList::DumpLocked(std::ostream& os) { diff --git a/src/thread_list.h b/src/thread_list.h index f0b4f6bc7a..9e45bfb228 100644 --- a/src/thread_list.h +++ b/src/thread_list.h @@ -64,6 +64,9 @@ class ThreadList { void ReleaseThreadId(uint32_t id); bool Contains(Thread* thread); + bool Contains(pid_t tid); + + void DumpUnattachedThreads(std::ostream& os); bool AllOtherThreadsAreDaemons(); void SuspendAllDaemonThreads(); |