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
diff --git a/src/thread_list.cc b/src/thread_list.cc
index e8b412c..3d0e0be 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 @@
   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 @@
 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) {