A little bit more of the threads implementation.

The most important change here is understanding that Thread's id_ field
was unrelated to java.lang.Thread's id field.

Change-Id: I832b92145332e1ded63a7824033dae684eeacf28
diff --git a/src/class_linker.cc b/src/class_linker.cc
index b8cd891..f312556 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -642,7 +642,7 @@
         return NULL;
       }
       ObjectLock lock(klass);
-      klass->SetClinitThreadId(self->GetId());
+      klass->SetClinitThreadId(self->GetTid());
       // Add the newly loaded class to the loaded classes table.
       bool success = InsertClass(descriptor, klass);  // TODO: just return collision
       if (!success) {
@@ -678,7 +678,7 @@
   if (!klass->IsLinked() && !klass->IsErroneous()) {
     ObjectLock lock(klass);
     // Check for circular dependencies between classes.
-    if (!klass->IsLinked() && klass->GetClinitThreadId() == self->GetId()) {
+    if (!klass->IsLinked() && klass->GetClinitThreadId() == self->GetTid()) {
       self->ThrowNewException("Ljava/lang/ClassCircularityError;", NULL); // TODO: detail
       return NULL;
     }
@@ -1210,7 +1210,7 @@
 
     while (klass->GetStatus() == Class::kStatusInitializing) {
       // we caught somebody else in the act; was it us?
-      if (klass->GetClinitThreadId() == self->GetId()) {
+      if (klass->GetClinitThreadId() == self->GetTid()) {
         LG << "recursive <clinit>";
         return true;
       }
@@ -1258,7 +1258,7 @@
 
     DCHECK(klass->GetStatus() < Class::kStatusInitializing);
 
-    klass->SetClinitThreadId(self->GetId());
+    klass->SetClinitThreadId(self->GetTid());
     klass->SetStatus(Class::kStatusInitializing);
   }
 
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index ef15e8e..5ea25e8 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -452,7 +452,7 @@
       : path_(path),
         handle_(handle),
         jni_on_load_lock_(Mutex::Create("JNI_OnLoad lock")),
-        jni_on_load_tid_(Thread::Current()->GetId()),
+        jni_on_load_thread_id_(Thread::Current()->GetThinLockId()),
         jni_on_load_result_(kPending) {
     pthread_cond_init(&jni_on_load_cond_, NULL);
   }
@@ -475,7 +475,7 @@
    */
   bool CheckOnLoadResult(JavaVMExt* vm) {
     Thread* self = Thread::Current();
-    if (jni_on_load_tid_ == self->GetId()) {
+    if (jni_on_load_thread_id_ == self->GetThinLockId()) {
       // Check this so we don't end up waiting for ourselves.  We need
       // to return "true" so the caller can continue.
       LOG(INFO) << *self << " recursive attempt to load library "
@@ -503,7 +503,7 @@
 
   void SetResult(bool result) {
     jni_on_load_result_ = result ? kOkay : kFailed;
-    jni_on_load_tid_ = 0;
+    jni_on_load_thread_id_ = 0;
 
     // Broadcast a wakeup to anybody sleeping on the condition variable.
     MutexLock mu(jni_on_load_lock_);
@@ -535,7 +535,7 @@
   // Wait for JNI_OnLoad in other thread.
   pthread_cond_t jni_on_load_cond_;
   // Recursive invocation guard.
-  uint32_t jni_on_load_tid_;
+  uint32_t jni_on_load_thread_id_;
   // Result of earlier JNI_OnLoad call.
   JNI_OnLoadState jni_on_load_result_;
 };
diff --git a/src/object.cc b/src/object.cc
index 8b0c976..4384a24 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -50,7 +50,7 @@
 }
 
 Class* Field::GetType() const {
-  DCHECK(Runtime::Current() != NULL)
+  DCHECK(Runtime::Current()->IsStarted())
       << "Can't call GetType without an initialized runtime";
   // Do full linkage (which sets dex cache value to speed next call)
   return Runtime::Current()->GetClassLinker()->ResolveType(GetTypeIdx(), this);
@@ -498,7 +498,7 @@
 
 void Class::SetStatus(Status new_status) {
   CHECK(new_status > GetStatus() || new_status == kStatusError ||
-        Runtime::Current() == NULL);  // no runtime implies we're not initialized
+      !Runtime::Current()->IsStarted());
   CHECK(sizeof(Status) == sizeof(uint32_t));
   return SetField32(OFFSET_OF_OBJECT_MEMBER(Class, status_),
                     new_status, false);
diff --git a/src/object.h b/src/object.h
index 8504612..050f571 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1519,7 +1519,7 @@
   Class* GetSuperClass() const {
     // Can only get super class for loaded classes (hack for when runtime is
     // initializing)
-    DCHECK(IsLoaded() || Runtime::Current() == NULL);
+    DCHECK(IsLoaded() || !Runtime::Current()->IsStarted());
     return GetFieldObject<Class*>(
         OFFSET_OF_OBJECT_MEMBER(Class, super_class_), false);
   }
@@ -1899,12 +1899,12 @@
 
   Field* FindDeclaredStaticField(const StringPiece& name, Class* type);
 
-  uint32_t GetClinitThreadId() const {
+  pid_t GetClinitThreadId() const {
     DCHECK(IsIdxLoaded());
     return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, clinit_thread_id_), false);
   }
 
-  void SetClinitThreadId(uint32_t new_clinit_thread_id) {
+  void SetClinitThreadId(pid_t new_clinit_thread_id) {
     SetField32(OFFSET_OF_OBJECT_MEMBER(Class, clinit_thread_id_),
                new_clinit_thread_id, false);
   }
@@ -1962,7 +1962,7 @@
   const Class* verify_error_class_;
 
   // threadId, used to check for recursive <clinit> invocation
-  uint32_t clinit_thread_id_;
+  pid_t clinit_thread_id_;
 
   // Total object size; used when allocating storage on gc heap.  (For
   // interfaces and abstract classes this will be zero.)
diff --git a/src/runtime.cc b/src/runtime.cc
index 2c2c5e2..c8f9036 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -22,6 +22,19 @@
 
 Runtime* Runtime::instance_ = NULL;
 
+Runtime::Runtime()
+    : stack_size_(0),
+      thread_list_(NULL),
+      intern_table_(NULL),
+      class_linker_(NULL),
+      signal_catcher_(NULL),
+      java_vm_(NULL),
+      started_(false),
+      vfprintf_(NULL),
+      exit_(NULL),
+      abort_(NULL) {
+}
+
 Runtime::~Runtime() {
   // TODO: use smart pointers instead. (we'll need the pimpl idiom.)
   delete class_linker_;
@@ -313,20 +326,24 @@
   if (Runtime::instance_ != NULL) {
     return NULL;
   }
-  UniquePtr<Runtime> runtime(new Runtime());
-  bool success = runtime->Init(options, ignore_unrecognized);
-  if (!success) {
-    return NULL;
+  instance_ = new Runtime;
+  if (!instance_->Init(options, ignore_unrecognized)) {
+    delete instance_;
+    instance_ = NULL;
   }
-  instance_ = runtime.release();
   return instance_;
 }
 
 void Runtime::Start() {
+  started_ = true;
   instance_->InitLibraries();
   instance_->signal_catcher_ = new SignalCatcher;
 }
 
+bool Runtime::IsStarted() {
+  return started_;
+}
+
 bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) {
   CHECK_EQ(sysconf(_SC_PAGE_SIZE), kPageSize);
 
@@ -361,7 +378,7 @@
     return false;
   }
 
-  thread_list_->Register(Thread::Attach(this));
+  thread_list_->Register(Thread::Attach(this, "main", false));
 
   class_linker_ = ClassLinker::Create(options->boot_class_path_,
                                       options->class_path_,
@@ -450,10 +467,7 @@
 }
 
 void Runtime::AttachCurrentThread(const char* name, JNIEnv** penv, bool as_daemon) {
-  if (as_daemon) {
-    UNIMPLEMENTED(WARNING) << "TODO: do something different for daemon threads";
-  }
-  Thread* t = Thread::Attach(instance_);
+  Thread* t = Thread::Attach(instance_, name, as_daemon);
   thread_list_->Register(t);
 }
 
diff --git a/src/runtime.h b/src/runtime.h
index 8a6ffe3..db86a96 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -68,6 +68,8 @@
   // Starts a runtime, which may cause threads to be started and code to run.
   void Start();
 
+  bool IsStarted();
+
   static Runtime* Current() {
     return instance_;
   }
@@ -119,8 +121,7 @@
  private:
   static void PlatformAbort(const char*, int);
 
-  Runtime() : stack_size_(0), thread_list_(NULL), intern_table_(NULL), class_linker_(NULL),
-    signal_catcher_(NULL) {}
+  Runtime();
 
   void BlockSignals();
 
@@ -141,6 +142,8 @@
 
   JavaVMExt* java_vm_;
 
+  bool started_;
+
   // Hooks supported by JNI_CreateJavaVM
   jint (*vfprintf_)(FILE* stream, const char* format, va_list ap);
   void (*exit_)(jint status);
diff --git a/src/thread.cc b/src/thread.cc
index 97cc8ea..b99e38a 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -6,6 +6,7 @@
 #include <sys/mman.h>
 
 #include <algorithm>
+#include <bitset>
 #include <cerrno>
 #include <iostream>
 #include <list>
@@ -216,6 +217,8 @@
 }
 
 Thread* Thread::Create(const Runtime* runtime) {
+  UNIMPLEMENTED(FATAL) << "need to pass in a java.lang.Thread";
+
   size_t stack_size = runtime->GetStackSize();
 
   Thread* new_thread = new Thread;
@@ -247,18 +250,48 @@
     PLOG(FATAL) << "pthread_attr_destroy failed";
   }
 
+  // TODO: get the "daemon" field from the java.lang.Thread.
+  // new_thread->is_daemon_ = dvmGetFieldBoolean(threadObj, gDvm.offJavaLangThread_daemon);
+
   return new_thread;
 }
 
-Thread* Thread::Attach(const Runtime* runtime) {
+static const uint32_t kMaxThreadId = ((1 << 16) - 1);
+std::bitset<kMaxThreadId> gAllocatedThreadIds;
+
+uint32_t AllocThreadId() {
+  Runtime::Current()->GetThreadList()->Lock();
+  for (size_t i = 0; i < gAllocatedThreadIds.size(); ++i) {
+    if (!gAllocatedThreadIds[i]) {
+      gAllocatedThreadIds.set(i);
+      Runtime::Current()->GetThreadList()->Unlock();
+      return i + 1; // Zero is reserved to mean "invalid".
+    }
+  }
+  LOG(FATAL) << "Out of internal thread ids";
+  return 0;
+}
+
+void ReleaseThreadId(uint32_t id) {
+  Runtime::Current()->GetThreadList()->Lock();
+  CHECK(gAllocatedThreadIds[id]);
+  gAllocatedThreadIds.reset(id);
+  Runtime::Current()->GetThreadList()->Unlock();
+}
+
+Thread* Thread::Attach(const Runtime* runtime, const char* name, bool as_daemon) {
   Thread* thread = new Thread;
   thread->InitCpu();
 
-  thread->handle_ = pthread_self();
+  thread->thin_lock_id_ = AllocThreadId();
   thread->tid_ = ::art::GetTid();
+  thread->handle_ = pthread_self();
+  thread->is_daemon_ = as_daemon;
 
   thread->state_ = kRunnable;
 
+  SetThreadName(name);
+
   errno = pthread_setspecific(Thread::pthread_key_self_, thread);
   if (errno != 0) {
     PLOG(FATAL) << "pthread_setspecific failed";
@@ -283,18 +316,19 @@
    */
   os << "TODO: pin Thread before dumping\n";
 #if 0
-  if (java_thread_ == NULL) {
+  // TODO: dalvikvm had this limitation, but we probably still want to do our best.
+  if (peer_ == NULL) {
     LOGI("Can't dump thread %d: threadObj not set", threadId);
     return;
   }
-  dvmAddTrackedAlloc(java_thread_, NULL);
+  dvmAddTrackedAlloc(peer_, NULL);
 #endif
 
   DumpState(os);
   DumpStack(os);
 
 #if 0
-  dvmReleaseTrackedAlloc(java_thread_, NULL);
+  dvmReleaseTrackedAlloc(peer_, NULL);
 #endif
 }
 
@@ -326,16 +360,22 @@
 void Thread::DumpState(std::ostream& os) const {
   std::string thread_name("unknown");
   int priority = -1;
-  bool is_daemon = false;
+
 #if 0 // TODO
   nameStr = (StringObject*) dvmGetFieldObject(threadObj, gDvm.offJavaLangThread_name);
   threadName = dvmCreateCstrFromString(nameStr);
   priority = dvmGetFieldInt(threadObj, gDvm.offJavaLangThread_priority);
-  is_daemon = dvmGetFieldBoolean(threadObj, gDvm.offJavaLangThread_daemon);
 #else
-  thread_name = "TODO";
+  {
+    // TODO: this may be truncated; we should use the java.lang.Thread 'name' field instead.
+    std::string stats;
+    if (ReadFileToString(StringPrintf("/proc/self/task/%d/stat", GetTid()).c_str(), &stats)) {
+      size_t start = stats.find('(') + 1;
+      size_t end = stats.find(')') - start;
+      thread_name = stats.substr(start, end);
+    }
+  }
   priority = -1;
-  is_daemon = false;
 #endif
 
   int policy;
@@ -362,20 +402,20 @@
 #endif
 
   os << '"' << thread_name << '"';
-  if (is_daemon) {
+  if (is_daemon_) {
     os << " daemon";
   }
   os << " prio=" << priority
-     << " tid=" << GetId()
+     << " tid=" << GetThinLockId()
      << " " << state_ << "\n";
 
   int suspend_count = 0; // TODO
   int debug_suspend_count = 0; // TODO
-  void* java_thread_ = NULL; // TODO
+  void* peer_ = NULL; // TODO
   os << "  | group=\"" << group_name << "\""
      << " sCount=" << suspend_count
      << " dsCount=" << debug_suspend_count
-     << " obj=" << reinterpret_cast<void*>(java_thread_)
+     << " obj=" << reinterpret_cast<void*>(peer_)
      << " self=" << reinterpret_cast<const void*>(this) << "\n";
   os << "  | sysTid=" << GetTid()
      << " nice=" << getpriority(PRIO_PROCESS, GetTid())
@@ -447,6 +487,19 @@
   }
 }
 
+Thread::Thread()
+    : thin_lock_id_(0),
+      peer_(NULL),
+      top_of_managed_stack_(),
+      native_to_managed_record_(NULL),
+      top_sirt_(NULL),
+      jni_env_(NULL),
+      exception_(NULL),
+      suspend_count_(0),
+      class_loader_override_(NULL) {
+  InitFunctionPointers();
+}
+
 Thread::~Thread() {
   delete jni_env_;
 }
@@ -747,7 +800,7 @@
   os << "Thread[" << &thread
      << ",pthread_t=" << thread.GetImpl()
      << ",tid=" << thread.GetTid()
-     << ",id=" << thread.GetId()
+     << ",id=" << thread.GetThinLockId()
      << ",state=" << thread.GetState() << "]";
   return os;
 }
@@ -785,15 +838,15 @@
   typedef std::list<Thread*>::const_iterator It; // TODO: C++0x auto
   for (It it = list_.begin(), end = list_.end(); it != end; ++it) {
     (*it)->Dump(os);
+    os << "\n";
   }
-  os << "\n";
 }
 
 void ThreadList::Register(Thread* thread) {
   //LOG(INFO) << "ThreadList::Register() " << *thread;
   MutexLock mu(lock_);
   CHECK(!Contains(thread));
-  list_.push_front(thread);
+  list_.push_back(thread);
 }
 
 void ThreadList::Unregister(Thread* thread) {
diff --git a/src/thread.h b/src/thread.h
index 87956b7..6b7e27c 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -236,7 +236,7 @@
   static Thread* Create(const Runtime* runtime);
 
   // Creates a new thread from the calling thread.
-  static Thread* Attach(const Runtime* runtime);
+  static Thread* Attach(const Runtime* runtime, const char* name, bool as_daemon);
 
   static Thread* Current() {
     void* thread = pthread_getspecific(Thread::pthread_key_self_);
@@ -260,8 +260,8 @@
     return true;
   }
 
-  uint32_t GetId() const {
-    return id_;
+  uint32_t GetThinLockId() const {
+    return thin_lock_id_;
   }
 
   pid_t GetTid() const {
@@ -324,14 +324,14 @@
     return ThreadOffset(OFFSETOF_MEMBER(Thread, self_));
   }
 
-  // Offset of exception within Thread, used by generated code
+  // Offset of exception_ within Thread, used by generated code
   static ThreadOffset ExceptionOffset() {
     return ThreadOffset(OFFSETOF_MEMBER(Thread, exception_));
   }
 
-  // Offset of id within Thread, used by generated code
+  // Offset of thin_lock_id_ within Thread, used by generated code
   static ThreadOffset IdOffset() {
-    return ThreadOffset(OFFSETOF_MEMBER(Thread, id_));
+    return ThreadOffset(OFFSETOF_MEMBER(Thread, thin_lock_id_));
   }
 
   // Offset of card_table within Thread, used by generated code
@@ -440,18 +440,7 @@
   void VisitRoots(Heap::RootVisitor* visitor, void* arg) const;
 
  private:
-  Thread()
-      : id_(1234),
-        top_of_managed_stack_(),
-        native_to_managed_record_(NULL),
-        top_sirt_(NULL),
-        jni_env_(NULL),
-        exception_(NULL),
-        suspend_count_(0),
-        class_loader_override_(NULL) {
-    InitFunctionPointers();
-  }
-
+  Thread();
   ~Thread();
   friend class Runtime;  // For ~Thread.
 
@@ -463,8 +452,12 @@
 
   void WalkStack(StackVisitor* visitor);
 
-  // Managed thread id.
-  uint32_t id_;
+  // Thin lock thread id. This is a small integer used by the thin lock implementation.
+  // This is not to be confused with the native thread's tid, nor is it the value returned
+  // by java.lang.Thread.getId --- this is a distinct value, used only for locking. One
+  // important difference between this id and the ids visible to managed code is that these
+  // ones get reused (to ensure that they fit in the number of bits available).
+  uint32_t thin_lock_id_;
 
   // System thread id.
   pid_t tid_;
@@ -472,6 +465,11 @@
   // Native thread handle.
   pthread_t handle_;
 
+  bool is_daemon_;
+
+  // Our managed peer (an instance of java.lang.Thread).
+  Object* peer_;
+
   // FIXME: placeholder for the gc cardTable
   uint32_t card_table_;
 
diff --git a/src/utils.cc b/src/utils.cc
index 90dd842..d890d29 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -12,6 +12,10 @@
 #include "object.h"
 #include "os.h"
 
+#if defined(HAVE_PRCTL)
+#include <sys/prctl.h>
+#endif
+
 namespace art {
 
 bool ReadFileToString(const std::string& file_name, std::string* result) {
@@ -213,6 +217,40 @@
   }
 }
 
+void SetThreadName(const char *threadName) {
+  int hasAt = 0;
+  int hasDot = 0;
+  const char *s = threadName;
+  while (*s) {
+    if (*s == '.') {
+      hasDot = 1;
+    } else if (*s == '@') {
+      hasAt = 1;
+    }
+    s++;
+  }
+  int len = s - threadName;
+  if (len < 15 || hasAt || !hasDot) {
+    s = threadName;
+  } else {
+    s = threadName + len - 15;
+  }
+#if defined(HAVE_ANDROID_PTHREAD_SETNAME_NP)
+  /* pthread_setname_np fails rather than truncating long strings */
+  char buf[16];       // MAX_TASK_COMM_LEN=16 is hard-coded into bionic
+  strncpy(buf, s, sizeof(buf)-1);
+  buf[sizeof(buf)-1] = '\0';
+  errno = pthread_setname_np(pthread_self(), buf);
+  if (errno != 0) {
+    PLOG(WARNING) << "Unable to set the name of current thread to '" << buf << "'";
+  }
+#elif defined(HAVE_PRCTL)
+  prctl(PR_SET_NAME, (unsigned long) s, 0, 0, 0);
+#else
+#error no implementation for SetThreadName
+#endif
+}
+
 }  // namespace art
 
 // Neither bionic nor glibc exposes gettid(2).
diff --git a/src/utils.h b/src/utils.h
index 69ca168..78d655e 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -180,6 +180,10 @@
 // Returns the calling thread's tid. (The C libraries don't expose this.)
 pid_t GetTid();
 
+// Sets the name of the current thread. The name may be truncated to an
+// implementation-defined limit.
+void SetThreadName(const char* name);
+
 }  // namespace art
 
 #endif  // ART_SRC_UTILS_H_