More threads work.

Adds stubs (and sometimes implementations) for dalvik.system.VMStack and
java.lang.Thread native methods. There was a bug in the dalvik
thread priority setting code, where the current thread and the passed-in
thread were confused.

I've also pulled Mutex and ThreadList out into their own files, and
moved some functionality around (with the aim of having more stuff
private, especially locks).

Change-Id: Ieb0f22669cac3df44ca34f7868f8e7d4dfa09ab6
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 3c203d4..f248029 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -64,6 +64,7 @@
 	src/compiler/codegen/arm/Assemble.cc \
 	src/compiler/codegen/arm/LocalOptimizations.cc \
 	src/compiler/codegen/arm/armv7-a/Codegen.cc \
+	src/dalvik_system_VMStack.cc \
 	src/dex_cache.cc \
 	src/dex_file.cc \
 	src/dex_instruction.cc \
@@ -79,6 +80,7 @@
 	src/java_lang_Runtime.cc \
 	src/java_lang_String.cc \
 	src/java_lang_System.cc \
+	src/java_lang_Thread.cc \
 	src/java_lang_Throwable.cc \
 	src/java_util_concurrent_atomic_AtomicLong.cc \
 	src/jni_compiler.cc \
@@ -92,6 +94,7 @@
 	src/managed_register_x86.cc \
 	src/memory_region.cc \
 	src/mspace.c \
+	src/mutex.cc \
 	src/object.cc \
 	src/object_bitmap.cc \
 	src/offsets.cc \
@@ -103,6 +106,7 @@
 	src/stringpiece.cc \
 	src/stringprintf.cc \
 	src/thread.cc \
+	src/thread_list.cc \
 	src/utf.cc \
 	src/utils.cc \
 	src/zip_archive.cc \
@@ -112,12 +116,14 @@
 	$(LIBART_COMMON_SRC_FILES) \
 	src/logging_android.cc \
 	src/runtime_android.cc \
+	src/thread_android.cc \
 	src/thread_arm.cc
 
 LIBART_HOST_SRC_FILES := \
 	$(LIBART_COMMON_SRC_FILES) \
 	src/logging_linux.cc \
 	src/runtime_linux.cc \
+	src/thread_linux.cc \
 	src/thread_x86.cc
 
 LIBARTTEST_COMMON_SRC_FILES := \
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 8595bfc..a8281a3 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -71,7 +71,7 @@
 }
 
 ClassLinker::ClassLinker(InternTable* intern_table)
-    : classes_lock_(Mutex::Create("ClassLinker::Lock")),
+    : classes_lock_("ClassLinker lock"),
       class_roots_(NULL),
       array_interfaces_(NULL),
       array_iftable_(NULL),
@@ -514,7 +514,6 @@
 }
 
 ClassLinker::~ClassLinker() {
-  delete classes_lock_;
   String::ResetClass();
   Field::ResetClass();
   Method::ResetClass();
diff --git a/src/class_linker.h b/src/class_linker.h
index e9606a7..fa0c789 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -10,8 +10,8 @@
 #include "dex_file.h"
 #include "heap.h"
 #include "macros.h"
+#include "mutex.h"
 #include "object.h"
-#include "thread.h"
 #include "unordered_map.h"
 #include "unordered_set.h"
 
@@ -264,9 +264,9 @@
   // multimap from a StringPiece hash code of a class descriptor to
   // Class* instances. Results should be compared for a matching
   // Class::descriptor_ and Class::class_loader_.
+  mutable Mutex classes_lock_;
   typedef std::tr1::unordered_multimap<size_t, Class*> Table;
   Table classes_;
-  Mutex* classes_lock_;
 
   // indexes into class_roots_.
   // needs to be kept in sync with class_roots_descriptors_.
diff --git a/src/dalvik_system_VMStack.cc b/src/dalvik_system_VMStack.cc
new file mode 100644
index 0000000..2a3f18b
--- /dev/null
+++ b/src/dalvik_system_VMStack.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jni_internal.h"
+#include "object.h"
+
+#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
+
+namespace art {
+
+namespace {
+
+jint VMStack_fillStackTraceElements(JNIEnv* env, jclass, jobject targetThread, jobjectArray javaSteArray) {
+  UNIMPLEMENTED(FATAL);
+  return 0;
+}
+
+jobject VMStack_getCallingClassLoader(JNIEnv* env, jclass) {
+  UNIMPLEMENTED(WARNING);
+  return NULL;
+}
+
+jobjectArray VMStack_getClasses(JNIEnv* env, jclass, jint maxDepth) {
+  UNIMPLEMENTED(FATAL);
+  return NULL;
+}
+
+jclass VMStack_getStackClass2(JNIEnv* env, jclass) {
+  UNIMPLEMENTED(FATAL);
+  return NULL;
+}
+
+jobjectArray VMStack_getThreadStackTrace(JNIEnv* env, jclass, jobject targetThread) {
+  UNIMPLEMENTED(FATAL);
+  return NULL;
+}
+
+static JNINativeMethod gMethods[] = {
+  NATIVE_METHOD(VMStack, fillStackTraceElements, "(Ljava/lang/Thread;[Ljava/lang/StackTraceElement;)I"),
+  NATIVE_METHOD(VMStack, getCallingClassLoader, "()Ljava/lang/ClassLoader;"),
+  NATIVE_METHOD(VMStack, getClasses, "(I)[Ljava/lang/Class;"),
+  NATIVE_METHOD(VMStack, getStackClass2, "()Ljava/lang/Class;"),
+  NATIVE_METHOD(VMStack, getThreadStackTrace, "(Ljava/lang/Thread;)[Ljava/lang/StackTraceElement;"),
+};
+
+}  // namespace
+
+void register_dalvik_system_VMStack(JNIEnv* env) {
+  jniRegisterNativeMethods(env, "dalvik/system/VMStack", gMethods, NELEM(gMethods));
+}
+
+}  // namespace art
diff --git a/src/heap.cc b/src/heap.cc
index 7f6b106..e346478 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -126,7 +126,7 @@
   // It's still to early to take a lock because there are no threads yet,
   // but we can create the heap lock now. We don't create it earlier to
   // make it clear that you can't use locks during heap initialization.
-  lock_ = Mutex::Create("Heap lock");
+  lock_ = new Mutex("Heap lock");
 }
 
 void Heap::Destroy() {
@@ -176,7 +176,7 @@
 #endif
 
 void Heap::VerifyObjectLocked(const Object* obj) {
-  DCHECK_LOCK_HELD(lock_);
+  lock_->AssertHeld();
   if (obj != NULL && !verify_object_disabled_) {
     if (!IsAligned(obj, kObjectAlignment)) {
       LOG(FATAL) << "Object isn't aligned: " << obj;
@@ -224,7 +224,7 @@
 void Heap::RecordAllocationLocked(Space* space, const Object* obj) {
 #ifndef NDEBUG
   if (Runtime::Current()->IsStarted()) {
-    DCHECK_LOCK_HELD(lock_);
+    lock_->AssertHeld();
   }
 #endif
   size_t size = space->AllocationSize(obj);
@@ -235,7 +235,7 @@
 }
 
 void Heap::RecordFreeLocked(Space* space, const Object* obj) {
-  DCHECK_LOCK_HELD(lock_);
+  lock_->AssertHeld();
   size_t size = space->AllocationSize(obj);
   DCHECK_NE(size, 0u);
   if (size < num_bytes_allocated_) {
@@ -263,7 +263,7 @@
 }
 
 Object* Heap::AllocateLocked(size_t size) {
-  DCHECK_LOCK_HELD(lock_);
+  lock_->AssertHeld();
   DCHECK(alloc_space_ != NULL);
   Space* space = alloc_space_;
   Object* obj = AllocateLocked(space, size);
@@ -274,7 +274,7 @@
 }
 
 Object* Heap::AllocateLocked(Space* space, size_t size) {
-  DCHECK_LOCK_HELD(lock_);
+  lock_->AssertHeld();
 
   // Fail impossible allocations.  TODO: collect soft references.
   if (size > maximum_size_) {
@@ -365,7 +365,7 @@
 }
 
 void Heap::CollectGarbageInternal() {
-  DCHECK_LOCK_HELD(lock_);
+  lock_->AssertHeld();
 
   // TODO: Suspend all threads
   {
@@ -402,14 +402,14 @@
 }
 
 void Heap::WaitForConcurrentGcToComplete() {
-  DCHECK_LOCK_HELD(lock_);
+  lock_->AssertHeld();
 }
 
 // Given the current contents of the active heap, increase the allowed
 // heap footprint to match the target utilization ratio.  This should
 // only be called immediately after a full garbage collection.
 void Heap::GrowForUtilization() {
-  DCHECK_LOCK_HELD(lock_);
+  lock_->AssertHeld();
   UNIMPLEMENTED(ERROR);
 }
 
diff --git a/src/intern_table.cc b/src/intern_table.cc
index 8a4e87e..41c1b2a 100644
--- a/src/intern_table.cc
+++ b/src/intern_table.cc
@@ -7,12 +7,7 @@
 
 namespace art {
 
-InternTable::InternTable() {
-  intern_table_lock_ = Mutex::Create("InternTable::Lock");
-}
-
-InternTable::~InternTable() {
-  delete intern_table_lock_;
+InternTable::InternTable() : intern_table_lock_("InternTable lock") {
 }
 
 size_t InternTable::Size() const {
@@ -30,7 +25,7 @@
 }
 
 const String* InternTable::Lookup(Table& table, const String* s, uint32_t hash_code) {
-  // Requires the intern_table_lock_.
+  intern_table_lock_.AssertHeld();
   typedef Table::const_iterator It; // TODO: C++0x auto
   for (It it = table.find(hash_code), end = table.end(); it != end; ++it) {
     const String* existing_string = it->second;
@@ -42,7 +37,7 @@
 }
 
 const String* InternTable::Insert(Table& table, const String* s, uint32_t hash_code) {
-  // Requires the intern_table_lock_.
+  intern_table_lock_.AssertHeld();
   table.insert(std::make_pair(hash_code, s));
   return s;
 }
@@ -53,7 +48,7 @@
 }
 
 void InternTable::Remove(Table& table, const String* s, uint32_t hash_code) {
-  // Requires the intern_table_lock_.
+  intern_table_lock_.AssertHeld();
   typedef Table::const_iterator It; // TODO: C++0x auto
   for (It it = table.find(hash_code), end = table.end(); it != end; ++it) {
     if (it->second == s) {
diff --git a/src/intern_table.h b/src/intern_table.h
index c9de228..fe84347 100644
--- a/src/intern_table.h
+++ b/src/intern_table.h
@@ -6,6 +6,7 @@
 #include "unordered_map.h"
 
 #include "heap.h"
+#include "mutex.h"
 #include "object.h"
 
 namespace art {
@@ -23,7 +24,6 @@
 class InternTable {
  public:
   InternTable();
-  ~InternTable();
 
   // Interns a potentially new string in the 'strong' table. (See above.)
   const String* InternStrong(int32_t utf16_length, const char* utf8_data);
@@ -59,9 +59,9 @@
   const String* Insert(Table& table, const String* s, uint32_t hash_code);
   void Remove(Table& table, const String* s, uint32_t hash_code);
 
+  mutable Mutex intern_table_lock_;
   Table strong_interns_;
   Table weak_interns_;
-  Mutex* intern_table_lock_;
 };
 
 }  // namespace art
diff --git a/src/java_lang_Thread.cc b/src/java_lang_Thread.cc
new file mode 100644
index 0000000..44578ee
--- /dev/null
+++ b/src/java_lang_Thread.cc
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jni_internal.h"
+#include "object.h"
+#include "thread.h"
+#include "thread_list.h"
+
+#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
+
+namespace art {
+
+namespace {
+
+jobject Thread_currentThread(JNIEnv* env, jclass) {
+  Object* peer = Decode<Object*>(env, Thread::Current()->GetPeer());
+  return AddLocalReference<jobject>(env, peer);
+}
+
+jboolean Thread_interrupted(JNIEnv* env, jclass) {
+  return Thread::Current()->Interrupted();
+}
+
+jboolean Thread_isInterrupted(JNIEnv* env, jobject javaThread) {
+  ThreadListLock lock;
+  Thread* thread = Thread::FromManagedThread(env, javaThread);
+  return thread->IsInterrupted();
+}
+
+void Thread_nativeCreate(JNIEnv* env, jclass, jobject javaThread, jlong stackSize) {
+  UNIMPLEMENTED(FATAL);
+  //Object* threadObj = dvmDecodeIndirectRef(env, javaThread);
+  //dvmCreateInterpThread(threadObj, (int) stackSize);
+}
+
+jint Thread_nativeGetStatus(JNIEnv* env, jobject javaThread) {
+  ThreadListLock lock;
+  Thread* thread = Thread::FromManagedThread(env, javaThread);
+  return static_cast<jint>(thread->GetState());
+}
+
+jboolean Thread_nativeHoldsLock(JNIEnv* env, jobject javaThread, jobject javaObject) {
+  ThreadListLock lock;
+  //Thread* thread = Thread::FromManagedThread(env, javaThread);
+  //Object* object = dvmDecodeIndirectRef(env, javaObject);
+  //if (object == NULL) {
+    //dvmThrowNullPointerException("object == null");
+    //return JNI_FALSE;
+  //}
+  //Thread* thread = Thread::FromManagedThread(env, javaThread);
+  //int result = dvmHoldsLock(thread, object);
+  //return result;
+  UNIMPLEMENTED(FATAL);
+  return JNI_FALSE;
+}
+
+void Thread_nativeInterrupt(JNIEnv* env, jobject javaThread) {
+  ThreadListLock lock;
+  UNIMPLEMENTED(FATAL);
+  //Thread* thread = Thread::FromManagedThread(env, javaThread);
+  //if (thread != NULL) {
+    //dvmThreadInterrupt(thread);
+  //}
+}
+
+void Thread_nativeSetName(JNIEnv* env, jobject javaThread, jstring javaName) {
+  ThreadListLock lock;
+  UNIMPLEMENTED(WARNING);
+  //Thread* thread = Thread::FromManagedThread(env, javaThread);
+  //StringObject* nameStr = (StringObject*) dvmDecodeIndirectRef(env, javaName);
+  //int threadId = (thread != NULL) ? thread->threadId : -1;
+  //dvmDdmSendThreadNameChange(threadId, nameStr);
+}
+
+/*
+ * Alter the priority of the specified thread.  "newPriority" will range
+ * from Thread.MIN_PRIORITY to Thread.MAX_PRIORITY (1-10), with "normal"
+ * threads at Thread.NORM_PRIORITY (5).
+ */
+void Thread_nativeSetPriority(JNIEnv* env, jobject javaThread, jint newPriority) {
+  ThreadListLock lock;
+  Thread* thread = Thread::FromManagedThread(env, javaThread);
+  thread->SetNativePriority(newPriority);
+}
+
+/*
+ * Causes the thread to temporarily pause and allow other threads to execute.
+ *
+ * The exact behavior is poorly defined.  Some discussion here:
+ *   http://www.cs.umd.edu/~pugh/java/memoryModel/archive/0944.html
+ */
+void Thread_yield(JNIEnv*, jobject) {
+  sched_yield();
+}
+
+static JNINativeMethod gMethods[] = {
+  NATIVE_METHOD(Thread, currentThread, "()Ljava/lang/Thread;"),
+  NATIVE_METHOD(Thread, interrupted, "()Z"),
+  NATIVE_METHOD(Thread, isInterrupted, "()Z"),
+  NATIVE_METHOD(Thread, nativeCreate, "(Ljava/lang/Thread;J)V"),
+  NATIVE_METHOD(Thread, nativeGetStatus, "()I"),
+  NATIVE_METHOD(Thread, nativeHoldsLock, "(Ljava/lang/Object;)Z"),
+  NATIVE_METHOD(Thread, nativeInterrupt, "()V"),
+  NATIVE_METHOD(Thread, nativeSetName, "(Ljava/lang/String;)V"),
+  NATIVE_METHOD(Thread, nativeSetPriority, "(I)V"),
+  NATIVE_METHOD(Thread, yield, "()V"),
+};
+
+}  // namespace
+
+void register_java_lang_Thread(JNIEnv* env) {
+  jniRegisterNativeMethods(env, "java/lang/Thread", gMethods, NELEM(gMethods));
+}
+
+}  // namespace art
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index c60dc24..83a147f 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -452,16 +452,12 @@
   SharedLibrary(const std::string& path, void* handle, Object* class_loader)
       : path_(path),
         handle_(handle),
-        jni_on_load_lock_(Mutex::Create("JNI_OnLoad lock")),
+        jni_on_load_lock_("JNI_OnLoad lock"),
         jni_on_load_thread_id_(Thread::Current()->GetThinLockId()),
         jni_on_load_result_(kPending) {
     pthread_cond_init(&jni_on_load_cond_, NULL);
   }
 
-  ~SharedLibrary() {
-    delete jni_on_load_lock_;
-  }
-
   Object* GetClassLoader() {
     return class_loader_;
   }
@@ -491,7 +487,7 @@
                   << "JNI_OnLoad...]";
       }
       ScopedThreadStateChange tsc(self, Thread::kWaiting); // TODO: VMWAIT
-      pthread_cond_wait(&jni_on_load_cond_, jni_on_load_lock_->GetImpl());
+      pthread_cond_wait(&jni_on_load_cond_, jni_on_load_lock_.GetImpl());
     }
 
     bool okay = (jni_on_load_result_ == kOkay);
@@ -532,7 +528,7 @@
   Object* class_loader_;
 
   // Guards remaining items.
-  Mutex* jni_on_load_lock_;
+  Mutex jni_on_load_lock_;
   // Wait for JNI_OnLoad in other thread.
   pthread_cond_t jni_on_load_cond_;
   // Recursive invocation guard.
@@ -2654,13 +2650,13 @@
       log_third_party_jni(options->IsVerbose("third-party-jni")),
       trace(options->jni_trace_),
       work_around_app_jni_bugs(false), // TODO: add a way to enable this
-      pins_lock(Mutex::Create("JNI pin table lock")),
+      pins_lock("JNI pin table lock"),
       pin_table("pin table", kPinTableInitialSize, kPinTableMaxSize),
-      globals_lock(Mutex::Create("JNI global reference table lock")),
+      globals_lock("JNI global reference table lock"),
       globals(kGlobalsInitial, kGlobalsMax, kGlobal),
-      weak_globals_lock(Mutex::Create("JNI weak global reference table lock")),
+      weak_globals_lock("JNI weak global reference table lock"),
       weak_globals(kWeakGlobalsInitial, kWeakGlobalsMax, kWeakGlobal),
-      libraries_lock(Mutex::Create("JNI shared libraries map lock")),
+      libraries_lock("JNI shared libraries map lock"),
       libraries(new Libraries) {
   functions = unchecked_functions = &gInvokeInterface;
   if (check_jni) {
@@ -2669,10 +2665,6 @@
 }
 
 JavaVMExt::~JavaVMExt() {
-  delete pins_lock;
-  delete globals_lock;
-  delete weak_globals_lock;
-  delete libraries_lock;
   delete libraries;
 }
 
diff --git a/src/jni_internal.h b/src/jni_internal.h
index a0fe8fc..a723b32 100644
--- a/src/jni_internal.h
+++ b/src/jni_internal.h
@@ -8,6 +8,7 @@
 #include "heap.h"
 #include "indirect_reference_table.h"
 #include "macros.h"
+#include "mutex.h"
 #include "reference_table.h"
 #include "runtime.h"
 
@@ -18,7 +19,6 @@
 class ClassLoader;
 class Libraries;
 class Method;
-class Mutex;
 class Thread;
 
 void JniAbort(const char* jni_function_name);
@@ -64,18 +64,18 @@
   bool work_around_app_jni_bugs;
 
   // Used to hold references to pinned primitive arrays.
-  Mutex* pins_lock;
+  Mutex pins_lock;
   ReferenceTable pin_table;
 
   // JNI global references.
-  Mutex* globals_lock;
+  Mutex globals_lock;
   IndirectReferenceTable globals;
 
   // JNI weak global references.
-  Mutex* weak_globals_lock;
+  Mutex weak_globals_lock;
   IndirectReferenceTable weak_globals;
 
-  Mutex* libraries_lock;
+  Mutex libraries_lock;
   Libraries* libraries;
 
   // Used by -Xcheck:jni.
diff --git a/src/logging.cc b/src/logging.cc
index 03788c3..5e9ae3a 100644
--- a/src/logging.cc
+++ b/src/logging.cc
@@ -22,8 +22,8 @@
 
 namespace {
 
-art::Mutex* GetLoggingLock() {
-  static art::Mutex* lock = art::Mutex::Create("LogMessage lock");
+art::Mutex& GetLoggingLock() {
+  static art::Mutex lock("LogMessage lock");
   return lock;
 }
 
diff --git a/src/logging.h b/src/logging.h
index 66190ac..43596b5 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -72,20 +72,8 @@
 #define DCHECK_STREQ(s1, s2) CHECK_STREQ(s1, s2)
 #define DCHECK_STRNE(s1, s2) CHECK_STRNE(s1, s2)
 
-  // These require "utils.h" and only work with bionic (not glibc).
-#ifdef __BIONIC__
-#define DCHECK_LOCK_HELD(l) CHECK_EQ(art::GetOwner(l->GetImpl()), art::GetTid())
-#define DCHECK_LOCK_NOT_HELD(l) CHECK_NE(art::GetOwner(l->GetImpl()), art::GetTid())
-#else
-#define DCHECK_LOCK_HELD(l)
-#define DCHECK_LOCK_NOT_HELD(l)
-#endif
-
 #else  // NDEBUG
 
-#define DCHECK_LOCK_HELD(l)
-#define DCHECK_LOCK_NOT_HELD(l)
-
 #define DCHECK(condition) \
   while (false) \
     CHECK(condition)
diff --git a/src/mutex.cc b/src/mutex.cc
new file mode 100644
index 0000000..4dba6b7
--- /dev/null
+++ b/src/mutex.cc
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mutex.h"
+
+#include <errno.h>
+
+#include "logging.h"
+#include "utils.h"
+
+namespace art {
+
+Mutex::Mutex(const char* name) : name_(name) {
+#ifndef NDEBUG
+  pthread_mutexattr_t debug_attributes;
+  errno = pthread_mutexattr_init(&debug_attributes);
+  if (errno != 0) {
+    PLOG(FATAL) << "pthread_mutexattr_init failed";
+  }
+#if VERIFY_OBJECT_ENABLED
+  errno = pthread_mutexattr_settype(&debug_attributes, PTHREAD_MUTEX_RECURSIVE);
+#else
+  errno = pthread_mutexattr_settype(&debug_attributes, PTHREAD_MUTEX_ERRORCHECK);
+#endif
+  if (errno != 0) {
+    PLOG(FATAL) << "pthread_mutexattr_settype failed";
+  }
+  errno = pthread_mutex_init(&mutex_, &debug_attributes);
+  if (errno != 0) {
+    PLOG(FATAL) << "pthread_mutex_init failed";
+  }
+  errno = pthread_mutexattr_destroy(&debug_attributes);
+  if (errno != 0) {
+    PLOG(FATAL) << "pthread_mutexattr_destroy failed";
+  }
+#else
+  errno = pthread_mutex_init(&mutex_, NULL);
+  if (errno != 0) {
+    PLOG(FATAL) << "pthread_mutex_init failed";
+  }
+#endif
+}
+
+Mutex::~Mutex() {
+  errno = pthread_mutex_destroy(&mutex_);
+  if (errno != 0) {
+    PLOG(FATAL) << "pthread_mutex_destroy failed";
+  }
+}
+
+void Mutex::Lock() {
+  int result = pthread_mutex_lock(&mutex_);
+  if (result != 0) {
+    errno = result;
+    PLOG(FATAL) << "pthread_mutex_lock failed";
+  }
+}
+
+bool Mutex::TryLock() {
+  int result = pthread_mutex_trylock(&mutex_);
+  if (result == EBUSY) {
+    return false;
+  }
+  if (result != 0) {
+    errno = result;
+    PLOG(FATAL) << "pthread_mutex_trylock failed";
+  }
+  return true;
+}
+
+void Mutex::Unlock() {
+  int result = pthread_mutex_unlock(&mutex_);
+  if (result != 0) {
+    errno = result;
+    PLOG(FATAL) << "pthread_mutex_unlock failed";
+  }
+}
+
+pid_t Mutex::GetOwner() {
+#ifdef __BIONIC__
+  return static_cast<pid_t>((mutex_.value >> 16) & 0xffff);
+#else
+  UNIMPLEMENTED(FATAL);
+  return 0;
+#endif
+}
+
+pid_t Mutex::GetTid() {
+  return art::GetTid();
+}
+
+}  // namespace
diff --git a/src/mutex.h b/src/mutex.h
new file mode 100644
index 0000000..cbfd5a0
--- /dev/null
+++ b/src/mutex.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_MUTEX_H_
+#define ART_SRC_MUTEX_H_
+
+#include <pthread.h>
+#include <string>
+
+#include "logging.h"
+#include "macros.h"
+
+namespace art {
+
+class Mutex {
+ public:
+  explicit Mutex(const char* name);
+  ~Mutex();
+
+  void Lock();
+
+  bool TryLock();
+
+  void Unlock();
+
+  const char* GetName() {
+    return name_.c_str();
+  }
+
+  pthread_mutex_t* GetImpl() {
+    return &mutex_;
+  }
+
+  void AssertHeld() {
+#ifdef __BIONIC__
+    DCHECK_EQ(GetOwner(), GetTid());
+#endif
+  }
+
+  void AssertNotHeld() {
+#ifdef __BIONIC__
+    DCHECK_NE(GetOwner(), GetTid());
+#endif
+  }
+
+ private:
+  pid_t GetOwner();
+  pid_t GetTid();
+
+  std::string name_;
+
+  pthread_mutex_t mutex_;
+
+  DISALLOW_COPY_AND_ASSIGN(Mutex);
+};
+
+class MutexLock {
+ public:
+  explicit MutexLock(Mutex& mu) : mu_(mu) {
+    mu_.Lock();
+  }
+
+  ~MutexLock() {
+    mu_.Unlock();
+  }
+
+ private:
+  Mutex& mu_;
+  DISALLOW_COPY_AND_ASSIGN(MutexLock);
+};
+
+}  // namespace art
+
+#endif  // ART_SRC_MUTEX_H_
diff --git a/src/runtime.cc b/src/runtime.cc
index 9517bc2..454a38c 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -14,6 +14,7 @@
 #include "jni_internal.h"
 #include "signal_catcher.h"
 #include "thread.h"
+#include "thread_list.h"
 
 // TODO: this drags in cutil/log.h, which conflicts with our logging.h.
 #include "JniConstants.h"
@@ -363,7 +364,7 @@
   abort_ = options->hook_abort_;
 
   default_stack_size_ = options->stack_size_;
-  thread_list_ = ThreadList::Create();
+  thread_list_ = new ThreadList;
 
   intern_table_ = new InternTable;
 
@@ -407,18 +408,17 @@
 
 void Runtime::RegisterRuntimeNativeMethods(JNIEnv* env) {
 #define REGISTER(FN) extern void FN(JNIEnv*); FN(env)
-  //REGISTER(register_dalvik_bytecode_OpcodeInfo);
   //REGISTER(register_dalvik_system_DexFile);
   //REGISTER(register_dalvik_system_VMDebug);
   //REGISTER(register_dalvik_system_VMRuntime);
-  //REGISTER(register_dalvik_system_VMStack);
+  REGISTER(register_dalvik_system_VMStack);
   //REGISTER(register_dalvik_system_Zygote);
   //REGISTER(register_java_lang_Class);
   REGISTER(register_java_lang_Object);
   REGISTER(register_java_lang_Runtime);
   REGISTER(register_java_lang_String);
   REGISTER(register_java_lang_System);
-  //REGISTER(register_java_lang_Thread);
+  REGISTER(register_java_lang_Thread);
   REGISTER(register_java_lang_Throwable);
   //REGISTER(register_java_lang_VMClassLoader);
   //REGISTER(register_java_lang_reflect_AccessibleObject);
@@ -434,7 +434,7 @@
 #undef REGISTER
 }
 
-void Runtime::DumpStatistics(std::ostream& os) {
+void Runtime::Dump(std::ostream& os) {
   // TODO: dump other runtime statistics?
   os << "Loaded classes: " << class_linker_->NumLoadedClasses() << "\n";
   os << "Intern table size: " << GetInternTable()->Size() << "\n";
@@ -445,6 +445,8 @@
   //    gDvm.pBootLoaderAlloc->curOffset);
   // LOGI("GC precise methods: %d", dvmPointerSetGetCount(gDvm.preciseMethods));
   os << "\n";
+
+  thread_list_->Dump(os);
 }
 
 void Runtime::BlockSignals() {
diff --git a/src/runtime.h b/src/runtime.h
index 99caa29..bcb118c 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -92,7 +92,7 @@
   // Detaches the current native thread from the runtime.
   void DetachCurrentThread();
 
-  void DumpStatistics(std::ostream& os);
+  void Dump(std::ostream& os);
 
   ~Runtime();
 
diff --git a/src/signal_catcher.cc b/src/signal_catcher.cc
index 1552180..7061b36 100644
--- a/src/signal_catcher.cc
+++ b/src/signal_catcher.cc
@@ -29,8 +29,7 @@
 
 namespace art {
 
-SignalCatcher::SignalCatcher() {
-  lock_ = Mutex::Create("SignalCatcher lock");
+SignalCatcher::SignalCatcher() : lock_("SignalCatcher lock") {
   SetHaltFlag(false);
 
   // Create a raw pthread; its start routine will attach to the runtime.
@@ -72,9 +71,7 @@
     os << "Cmd line: " << cmdline << "\n";
   }
 
-  Runtime* runtime = Runtime::Current();
-  runtime->DumpStatistics(os);
-  runtime->GetThreadList()->Dump(os);
+  Runtime::Current()->Dump(os);
 
   std::string maps;
   if (ReadFileToString("/proc/self/maps", &maps)) {
diff --git a/src/signal_catcher.h b/src/signal_catcher.h
index 8d91a94..dc05d06 100644
--- a/src/signal_catcher.h
+++ b/src/signal_catcher.h
@@ -17,11 +17,10 @@
 #ifndef ART_SRC_SIGNAL_CATCHER_H_
 #define ART_SRC_SIGNAL_CATCHER_H_
 
-#include <pthread.h>
+#include "mutex.h"
 
 namespace art {
 
-class Mutex;
 class Runtime;
 class Thread;
 
@@ -44,7 +43,7 @@
   void SetHaltFlag(bool new_value);
   bool ShouldHalt();
 
-  Mutex* lock_;
+  mutable Mutex lock_;
   bool halt_;
   pthread_t thread_;
 };
diff --git a/src/thread.cc b/src/thread.cc
index 78cb1c6..4b477b8 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -17,6 +17,7 @@
 #include "object.h"
 #include "runtime.h"
 #include "runtime_support.h"
+#include "thread_list.h"
 #include "utils.h"
 
 namespace art {
@@ -310,74 +311,6 @@
   pDebugMe = DebugMe;
 }
 
-Mutex::~Mutex() {
-  errno = pthread_mutex_destroy(&mutex_);
-  if (errno != 0) {
-    PLOG(FATAL) << "pthread_mutex_destroy failed";
-  }
-}
-
-Mutex* Mutex::Create(const char* name) {
-  Mutex* mu = new Mutex(name);
-#ifndef NDEBUG
-  pthread_mutexattr_t debug_attributes;
-  errno = pthread_mutexattr_init(&debug_attributes);
-  if (errno != 0) {
-    PLOG(FATAL) << "pthread_mutexattr_init failed";
-  }
-#if VERIFY_OBJECT_ENABLED
-  errno = pthread_mutexattr_settype(&debug_attributes, PTHREAD_MUTEX_RECURSIVE);
-#else
-  errno = pthread_mutexattr_settype(&debug_attributes, PTHREAD_MUTEX_ERRORCHECK);
-#endif
-  if (errno != 0) {
-    PLOG(FATAL) << "pthread_mutexattr_settype failed";
-  }
-  errno = pthread_mutex_init(&mu->mutex_, &debug_attributes);
-  if (errno != 0) {
-    PLOG(FATAL) << "pthread_mutex_init failed";
-  }
-  errno = pthread_mutexattr_destroy(&debug_attributes);
-  if (errno != 0) {
-    PLOG(FATAL) << "pthread_mutexattr_destroy failed";
-  }
-#else
-  errno = pthread_mutex_init(&mu->mutex_, NULL);
-  if (errno != 0) {
-    PLOG(FATAL) << "pthread_mutex_init failed";
-  }
-#endif
-  return mu;
-}
-
-void Mutex::Lock() {
-  int result = pthread_mutex_lock(&mutex_);
-  if (result != 0) {
-    errno = result;
-    PLOG(FATAL) << "pthread_mutex_lock failed";
-  }
-}
-
-bool Mutex::TryLock() {
-  int result = pthread_mutex_trylock(&mutex_);
-  if (result == EBUSY) {
-    return false;
-  }
-  if (result != 0) {
-    errno = result;
-    PLOG(FATAL) << "pthread_mutex_trylock failed";
-  }
-  return true;
-}
-
-void Mutex::Unlock() {
-  int result = pthread_mutex_unlock(&mutex_);
-  if (result != 0) {
-    errno = result;
-    PLOG(FATAL) << "pthread_mutex_unlock failed";
-  }
-}
-
 void Frame::Next() {
   byte* next_sp = reinterpret_cast<byte*>(sp_) +
       GetMethod()->GetFrameSizeInBytes();
@@ -478,15 +411,14 @@
 
   jobject thread_group = NULL;
   jobject thread_name = env->NewStringUTF(name);
-  jint thread_priority = 123;
+  jint thread_priority = GetNativePriority();
   jboolean thread_is_daemon = as_daemon;
 
   jclass c = env->FindClass("java/lang/Thread");
   jmethodID mid = env->GetMethodID(c, "<init>", "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V");
-  jobject o = env->NewObject(c, mid, thread_group, thread_name, thread_priority, thread_is_daemon);
-  LOG(INFO) << "Created new java.lang.Thread " << (void*) o << " decoded=" << (void*) DecodeJObject(o);
 
-  peer_ = DecodeJObject(o);
+  jobject peer = env->NewObject(c, mid, thread_group, thread_name, thread_priority, thread_is_daemon);
+  peer_ = env->NewGlobalRef(peer);
 }
 
 void Thread::InitStackHwm() {
@@ -631,7 +563,6 @@
 
   int suspend_count = 0; // TODO
   int debug_suspend_count = 0; // TODO
-  void* peer_ = NULL; // TODO
   os << "  | group=\"" << group_name << "\""
      << " sCount=" << suspend_count
      << " dsCount=" << debug_suspend_count
@@ -706,6 +637,10 @@
 
 Thread::Thread()
     : peer_(NULL),
+      wait_mutex_("Thread wait mutex"),
+      wait_monitor_(NULL),
+      interrupted_(false),
+      stack_end_(NULL),
       top_of_managed_stack_(),
       native_to_managed_record_(NULL),
       top_sirt_(NULL),
@@ -714,11 +649,8 @@
       suspend_count_(0),
       class_loader_override_(NULL) {
   InitCpu();
-  {
-    ThreadListLock mu;
-    thin_lock_id_ = Runtime::Current()->GetThreadList()->AllocThreadId();
-  }
   InitFunctionPointers();
+  thin_lock_id_ = Runtime::Current()->GetThreadList()->AllocThreadId();
 }
 
 void MonitorExitVisitor(const Object* object, void*) {
@@ -754,6 +686,10 @@
   //dvmUnlockObject(self, lock);
   //lock = NULL;
 
+  // Delete our global reference to the java.lang.Thread.
+  jni_env_->DeleteGlobalRef(peer_);
+  peer_ = NULL;
+
   delete jni_env_;
   jni_env_ = NULL;
 
@@ -1057,102 +993,10 @@
      << ",pthread_t=" << thread.GetImpl()
      << ",tid=" << thread.GetTid()
      << ",id=" << thread.GetThinLockId()
-     << ",state=" << thread.GetState() << "]";
+     << ",state=" << thread.GetState()
+     << ",peer=" << thread.GetPeer()
+     << "]";
   return os;
 }
 
-ThreadList* ThreadList::Create() {
-  return new ThreadList;
-}
-
-ThreadList::ThreadList() {
-  lock_ = Mutex::Create("ThreadList::Lock");
-}
-
-ThreadList::~ThreadList() {
-  if (Contains(Thread::Current())) {
-    Runtime::Current()->DetachCurrentThread();
-  }
-
-  // All threads should have exited and unregistered when we
-  // reach this point. This means that all daemon threads had been
-  // shutdown cleanly.
-  // TODO: dump ThreadList if non-empty.
-  CHECK_EQ(list_.size(), 0U);
-
-  delete lock_;
-  lock_ = NULL;
-}
-
-bool ThreadList::Contains(Thread* thread) {
-  return find(list_.begin(), list_.end(), thread) != list_.end();
-}
-
-void ThreadList::Dump(std::ostream& os) {
-  MutexLock mu(lock_);
-  os << "DALVIK THREADS (" << list_.size() << "):\n";
-  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";
-  }
-}
-
-void ThreadList::Register(Thread* thread) {
-  //LOG(INFO) << "ThreadList::Register() " << *thread;
-  MutexLock mu(lock_);
-  CHECK(!Contains(thread));
-  list_.push_back(thread);
-}
-
-void ThreadList::Unregister() {
-  Thread* self = Thread::Current();
-
-  //LOG(INFO) << "ThreadList::Unregister() " << self;
-  MutexLock mu(lock_);
-
-  // Remove this thread from the list.
-  CHECK(Contains(self));
-  list_.remove(self);
-
-  // Delete the Thread* and release the thin lock id.
-  uint32_t thin_lock_id = self->thin_lock_id_;
-  delete self;
-  ReleaseThreadId(thin_lock_id);
-
-  // Clear the TLS data, so that thread is recognizably detached.
-  // (It may wish to reattach later.)
-  errno = pthread_setspecific(Thread::pthread_key_self_, NULL);
-  if (errno != 0) {
-    PLOG(FATAL) << "pthread_setspecific failed";
-  }
-}
-
-void ThreadList::VisitRoots(Heap::RootVisitor* visitor, void* arg) const {
-  MutexLock mu(lock_);
-  typedef std::list<Thread*>::const_iterator It; // TODO: C++0x auto
-  for (It it = list_.begin(), end = list_.end(); it != end; ++it) {
-    (*it)->VisitRoots(visitor, arg);
-  }
-}
-
-uint32_t ThreadList::AllocThreadId() {
-  DCHECK_LOCK_HELD(lock_);
-  for (size_t i = 0; i < allocated_ids_.size(); ++i) {
-    if (!allocated_ids_[i]) {
-      allocated_ids_.set(i);
-      return i + 1; // Zero is reserved to mean "invalid".
-    }
-  }
-  LOG(FATAL) << "Out of internal thread ids";
-  return 0;
-}
-
-void ThreadList::ReleaseThreadId(uint32_t id) {
-  DCHECK_LOCK_HELD(lock_);
-  --id; // Zero is reserved to mean "invalid".
-  DCHECK(allocated_ids_[id]) << id;
-  allocated_ids_.reset(id);
-}
-
-}  // namespace
+}  // namespace art
diff --git a/src/thread.h b/src/thread.h
index 4d27151..3f6228a 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -8,12 +8,14 @@
 #include <bitset>
 #include <iosfwd>
 #include <list>
+#include <string>
 
 #include "dex_file.h"
 #include "globals.h"
 #include "jni_internal.h"
 #include "logging.h"
 #include "macros.h"
+#include "mutex.h"
 #include "mem_map.h"
 #include "offsets.h"
 
@@ -24,6 +26,7 @@
 class ClassLinker;
 class ClassLoader;
 class Method;
+class Monitor;
 class Object;
 class Runtime;
 class Thread;
@@ -36,43 +39,6 @@
 template<class T> class PrimitiveArray;
 typedef PrimitiveArray<int32_t> IntArray;
 
-class Mutex {
- public:
-  ~Mutex();
-
-  void Lock();
-
-  bool TryLock();
-
-  void Unlock();
-
-  const char* GetName() { return name_; }
-
-  static Mutex* Create(const char* name);
-
-  pthread_mutex_t* GetImpl() { return &mutex_; }
-
- private:
-  explicit Mutex(const char* name) : name_(name) {}
-
-  const char* name_;
-
-  pthread_mutex_t mutex_;
-
-  DISALLOW_COPY_AND_ASSIGN(Mutex);
-};
-
-class MutexLock {
- public:
-  explicit MutexLock(Mutex *mu) : mu_(mu) {
-    mu_->Lock();
-  }
-  ~MutexLock() { mu_->Unlock(); }
- private:
-  Mutex* const mu_;
-  DISALLOW_COPY_AND_ASSIGN(MutexLock);
-};
-
 // Stack allocated indirect reference table, allocated within the bridge frame
 // between managed and native code.
 class StackIndirectReferenceTable {
@@ -155,6 +121,12 @@
 
 class Thread {
  public:
+  /* thread priorities, from java.lang.Thread */
+  enum Priority {
+    kMinPriority = 1,
+    kNormPriority = 5,
+    kMaxPriority = 10,
+  };
   enum State {
     kUnknown = -1,
     kNew,
@@ -250,6 +222,13 @@
     return reinterpret_cast<Thread*>(thread);
   }
 
+  static Thread* FromManagedThread(JNIEnv* env, jobject thread) {
+    // TODO: make these more generally available, and cached.
+    jclass java_lang_Thread = env->FindClass("java/lang/Thread");
+    jfieldID fid = env->GetFieldID(java_lang_Thread, "vmData", "I");
+    return reinterpret_cast<Thread*>(static_cast<uintptr_t>(env->GetIntField(thread, fid)));
+  }
+
   void Dump(std::ostream& os) const;
 
   State GetState() const {
@@ -262,6 +241,22 @@
     return old_state;
   }
 
+  /*
+   * Changes the priority of this thread to match that of the java.lang.Thread object.
+   *
+   * We map a priority value from 1-10 to Linux "nice" values, where lower
+   * numbers indicate higher priority.
+   */
+  void SetNativePriority(int newPriority);
+
+  /*
+   * Returns the thread priority for the current thread by querying the system.
+   * This is useful when attaching a thread through JNI.
+   *
+   * Returns a value from 1 to 10 (compatible with java.lang.Thread values).
+   */
+  static int GetNativePriority();
+
   bool CanAccessDirectReferences() const {
     // TODO: when we have a moving collector, we'll need: return state_ == kRunnable;
     return true;
@@ -279,6 +274,10 @@
     return pthread_;
   }
 
+  jobject GetPeer() const {
+    return peer_;
+  }
+
   // Returns the Method* for the current method.
   // This is used by the JNI implementation for logging and diagnostic purposes.
   const Method* GetCurrentMethod() const {
@@ -353,6 +352,20 @@
   // Convert a jobject into a Object*
   Object* DecodeJObject(jobject obj);
 
+  // Implements java.lang.Thread.interrupted.
+  bool Interrupted() {
+    MutexLock mu(wait_mutex_);
+    bool interrupted = interrupted_;
+    interrupted_ = false;
+    return interrupted;
+  }
+
+  // Implements java.lang.Thread.isInterrupted.
+  bool IsInterrupted() {
+    MutexLock mu(wait_mutex_);
+    return interrupted_;
+  }
+
   void RegisterExceptionEntryPoint(void (*handler)(Method**)) {
     exception_entry_point_ = handler;
   }
@@ -480,7 +493,14 @@
   bool is_daemon_;
 
   // Our managed peer (an instance of java.lang.Thread).
-  Object* peer_;
+  jobject peer_;
+
+  // Guards the 'interrupted_' and 'wait_monitor_' members.
+  mutable Mutex wait_mutex_;
+  // Pointer to the monitor lock we're currently waiting on (or NULL), guarded by wait_mutex_.
+  Monitor* wait_monitor_;
+  // Thread "interrupted" status; stays raised until queried or thrown, guarded by wait_mutex_.
+  bool interrupted_;
 
   // FIXME: placeholder for the gc cardTable
   uint32_t card_table_;
@@ -538,79 +558,6 @@
 std::ostream& operator<<(std::ostream& os, const Thread& thread);
 std::ostream& operator<<(std::ostream& os, const Thread::State& state);
 
-class ThreadList {
- public:
-  static const uint32_t kMaxThreadId = 0xFFFF;
-  static const uint32_t kInvalidId = 0;
-  static const uint32_t kMainId = 1;
-
-  static ThreadList* Create();
-
-  ~ThreadList();
-
-  void Dump(std::ostream& os);
-
-  void Register(Thread* thread);
-
-  void Unregister();
-
-  bool Contains(Thread* thread);
-
-  void VisitRoots(Heap::RootVisitor* visitor, void* arg) const;
-
- private:
-  ThreadList();
-
-  uint32_t AllocThreadId();
-  void ReleaseThreadId(uint32_t id);
-
-  void Lock() {
-    lock_->Lock();
-  }
-
-  void Unlock() {
-    lock_->Unlock();
-  }
-
-  Mutex* lock_;
-
-  std::bitset<kMaxThreadId> allocated_ids_;
-  std::list<Thread*> list_;
-
-  friend class Thread;
-  friend class ThreadListLock;
-
-  DISALLOW_COPY_AND_ASSIGN(ThreadList);
-};
-
-class ThreadListLock {
- public:
-  ThreadListLock(Thread* self = NULL) {
-    if (self == NULL) {
-      // Try to get it from TLS.
-      self = Thread::Current();
-    }
-    Thread::State old_state;
-    if (self != NULL) {
-      old_state = self->SetState(Thread::kWaiting);  // TODO: VMWAIT
-    } else {
-      // This happens during VM shutdown.
-      old_state = Thread::kUnknown;
-    }
-    Runtime::Current()->GetThreadList()->Lock();
-    if (self != NULL) {
-      self->SetState(old_state);
-    }
-  }
-
-  ~ThreadListLock() {
-    Runtime::Current()->GetThreadList()->Unlock();
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ThreadListLock);
-};
-
 class ScopedThreadStateChange {
  public:
   ScopedThreadStateChange(Thread* thread, Thread::State new_state) : thread_(thread) {
diff --git a/src/thread_android.cc b/src/thread_android.cc
new file mode 100644
index 0000000..295a509
--- /dev/null
+++ b/src/thread_android.cc
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "thread.h"
+
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <limits.h>
+#include <errno.h>
+
+#include <cutils/sched_policy.h>
+#include <utils/threads.h>
+
+#include "macros.h"
+
+namespace art {
+
+/*
+ * Conversion map for "nice" values.
+ *
+ * We use Android thread priority constants to be consistent with the rest
+ * of the system.  In some cases adjacent entries may overlap.
+ */
+static const int kNiceValues[10] = {
+  ANDROID_PRIORITY_LOWEST,                /* 1 (MIN_PRIORITY) */
+  ANDROID_PRIORITY_BACKGROUND + 6,
+  ANDROID_PRIORITY_BACKGROUND + 3,
+  ANDROID_PRIORITY_BACKGROUND,
+  ANDROID_PRIORITY_NORMAL,                /* 5 (NORM_PRIORITY) */
+  ANDROID_PRIORITY_NORMAL - 2,
+  ANDROID_PRIORITY_NORMAL - 4,
+  ANDROID_PRIORITY_URGENT_DISPLAY + 3,
+  ANDROID_PRIORITY_URGENT_DISPLAY + 2,
+  ANDROID_PRIORITY_URGENT_DISPLAY         /* 10 (MAX_PRIORITY) */
+};
+
+void Thread::SetNativePriority(int newPriority) {
+  if (newPriority < 1 || newPriority > 10) {
+    LOG(WARNING) << "bad priority " << newPriority;
+    newPriority = 5;
+  }
+
+  int newNice = kNiceValues[newPriority-1];
+  pid_t tid = GetTid();
+
+  if (newNice >= ANDROID_PRIORITY_BACKGROUND) {
+    set_sched_policy(tid, SP_BACKGROUND);
+  } else if (getpriority(PRIO_PROCESS, tid) >= ANDROID_PRIORITY_BACKGROUND) {
+    set_sched_policy(tid, SP_FOREGROUND);
+  }
+
+  if (setpriority(PRIO_PROCESS, tid, newNice) != 0) {
+    PLOG(INFO) << *this << " setPriority(PRIO_PROCESS, " << tid << ", " << newNice << ") failed";
+  }
+}
+
+int Thread::GetNativePriority() {
+  errno = 0;
+  int native_priority = getpriority(PRIO_PROCESS, 0);
+  if (native_priority == -1 && errno != 0) {
+    PLOG(WARNING) << "getpriority failed";
+    return Thread::kNormPriority;
+  }
+
+  int managed_priority = Thread::kMinPriority;
+  for (size_t i = 0; i < arraysize(kNiceValues); i++) {
+    if (native_priority >= kNiceValues[i]) {
+      break;
+    }
+    managed_priority++;
+  }
+  if (managed_priority > Thread::kMaxPriority) {
+    managed_priority = Thread::kMaxPriority;
+  }
+  return managed_priority;
+}
+
+}  // namespace art
diff --git a/src/thread_linux.cc b/src/thread_linux.cc
new file mode 100644
index 0000000..2bbbb25
--- /dev/null
+++ b/src/thread_linux.cc
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "thread.h"
+
+namespace art {
+
+void Thread::SetNativePriority(int) {
+  // Do nothing.
+}
+
+int Thread::GetNativePriority() {
+  return Thread::kNormPriority;
+}
+
+}  // namespace art
diff --git a/src/thread_list.cc b/src/thread_list.cc
new file mode 100644
index 0000000..b0626c7
--- /dev/null
+++ b/src/thread_list.cc
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "thread_list.h"
+
+namespace art {
+
+ThreadList::ThreadList() : lock_("ThreadList lock") {
+}
+
+ThreadList::~ThreadList() {
+  if (Contains(Thread::Current())) {
+    Runtime::Current()->DetachCurrentThread();
+  }
+
+  // All threads should have exited and unregistered when we
+  // reach this point. This means that all daemon threads had been
+  // shutdown cleanly.
+  // TODO: dump ThreadList if non-empty.
+  CHECK_EQ(list_.size(), 0U);
+}
+
+bool ThreadList::Contains(Thread* thread) {
+  return find(list_.begin(), list_.end(), thread) != list_.end();
+}
+
+void ThreadList::Dump(std::ostream& os) {
+  MutexLock mu(lock_);
+  os << "DALVIK THREADS (" << list_.size() << "):\n";
+  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";
+  }
+}
+
+void ThreadList::Register(Thread* thread) {
+  //LOG(INFO) << "ThreadList::Register() " << *thread;
+  MutexLock mu(lock_);
+  CHECK(!Contains(thread));
+  list_.push_back(thread);
+}
+
+void ThreadList::Unregister() {
+  Thread* self = Thread::Current();
+
+  //LOG(INFO) << "ThreadList::Unregister() " << self;
+  MutexLock mu(lock_);
+
+  // Remove this thread from the list.
+  CHECK(Contains(self));
+  list_.remove(self);
+
+  // Delete the Thread* and release the thin lock id.
+  uint32_t thin_lock_id = self->thin_lock_id_;
+  delete self;
+  ReleaseThreadId(thin_lock_id);
+
+  // Clear the TLS data, so that thread is recognizably detached.
+  // (It may wish to reattach later.)
+  errno = pthread_setspecific(Thread::pthread_key_self_, NULL);
+  if (errno != 0) {
+    PLOG(FATAL) << "pthread_setspecific failed";
+  }
+}
+
+void ThreadList::VisitRoots(Heap::RootVisitor* visitor, void* arg) const {
+  MutexLock mu(lock_);
+  typedef std::list<Thread*>::const_iterator It; // TODO: C++0x auto
+  for (It it = list_.begin(), end = list_.end(); it != end; ++it) {
+    (*it)->VisitRoots(visitor, arg);
+  }
+}
+
+uint32_t ThreadList::AllocThreadId() {
+  MutexLock mu(lock_);
+  for (size_t i = 0; i < allocated_ids_.size(); ++i) {
+    if (!allocated_ids_[i]) {
+      allocated_ids_.set(i);
+      return i + 1; // Zero is reserved to mean "invalid".
+    }
+  }
+  LOG(FATAL) << "Out of internal thread ids";
+  return 0;
+}
+
+void ThreadList::ReleaseThreadId(uint32_t id) {
+  lock_.AssertHeld();
+  --id; // Zero is reserved to mean "invalid".
+  DCHECK(allocated_ids_[id]) << id;
+  allocated_ids_.reset(id);
+}
+
+}  // namespace art
diff --git a/src/thread_list.h b/src/thread_list.h
new file mode 100644
index 0000000..12fdde4
--- /dev/null
+++ b/src/thread_list.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_THREAD_LIST_H_
+#define ART_SRC_THREAD_LIST_H_
+
+#include "mutex.h"
+#include "thread.h"
+
+namespace art {
+
+class ThreadList {
+ public:
+  static const uint32_t kMaxThreadId = 0xFFFF;
+  static const uint32_t kInvalidId = 0;
+  static const uint32_t kMainId = 1;
+
+  ThreadList();
+  ~ThreadList();
+
+  void Dump(std::ostream& os);
+
+  void Register(Thread* thread);
+
+  void Unregister();
+
+  bool Contains(Thread* thread);
+
+  void VisitRoots(Heap::RootVisitor* visitor, void* arg) const;
+
+ private:
+  uint32_t AllocThreadId();
+  void ReleaseThreadId(uint32_t id);
+
+  mutable Mutex lock_;
+  std::bitset<kMaxThreadId> allocated_ids_;
+  std::list<Thread*> list_;
+
+  friend class Thread;
+  friend class ThreadListLock;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadList);
+};
+
+class ThreadListLock {
+ public:
+  ThreadListLock(Thread* self = NULL) {
+    if (self == NULL) {
+      // Try to get it from TLS.
+      self = Thread::Current();
+    }
+    Thread::State old_state;
+    if (self != NULL) {
+      old_state = self->SetState(Thread::kWaiting);  // TODO: VMWAIT
+    } else {
+      // This happens during VM shutdown.
+      old_state = Thread::kUnknown;
+    }
+    Runtime::Current()->GetThreadList()->lock_.Lock();
+    if (self != NULL) {
+      self->SetState(old_state);
+    }
+  }
+
+  ~ThreadListLock() {
+    Runtime::Current()->GetThreadList()->lock_.Unlock();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ThreadListLock);
+};
+
+}  // namespace art
+
+#endif  // ART_SRC_THREAD_LIST_H_
diff --git a/src/utils.cc b/src/utils.cc
index fed8a5e..d146166 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -252,15 +252,6 @@
 #endif
 }
 
-pid_t GetOwner(pthread_mutex_t* mutex) {
-#ifdef __BIONIC__
-  return static_cast<pid_t>(((mutex)->value >> 16) & 0xffff);
-#else
-  UNIMPLEMENTED(FATAL);
-  return 0;
-#endif
-}
-
 }  // namespace art
 
 // Neither bionic nor glibc exposes gettid(2).
diff --git a/src/utils.h b/src/utils.h
index 135ea59..e6ed1d2 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -181,9 +181,6 @@
 // Returns the calling thread's tid. (The C libraries don't expose this.)
 pid_t GetTid();
 
-// Returns the tid of the thread that owns the given pthread mutex, or 0.
-pid_t GetOwner(pthread_mutex_t* mutex);
-
 // Sets the name of the current thread. The name may be truncated to an
 // implementation-defined limit.
 void SetThreadName(const char* name);