Add more functionality to the thread and mutex implementation.

Change-Id: I33b2e53acb4c4c6653f13f1bbdd77cc7ce27e581
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 4798d63..30a63ca 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -49,7 +49,8 @@
 	src/object.cc \
 	src/raw_dex_file.cc \
 	src/runtime.cc \
-	src/stringpiece.cc
+	src/stringpiece.cc \
+	src/thread.cc
 
 ifeq ($(LIBART_TARGET_ARCH),arm)
 LIBART_LOCAL_SRC_FILES += \
diff --git a/src/class_linker.cc b/src/class_linker.cc
index e1e9bef..cf72a11 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -41,7 +41,7 @@
 Class* ClassLinker::FindClass(const char* descriptor,
                               Object* class_loader,
                               DexFile* dex_file) {
-  Thread* self = Thread::Self();
+  Thread* self = Thread::Current();
   CHECK(!self->IsExceptionPending());
   // Find the class in the loaded classes table.
   Class* klass = LookupClass(descriptor, class_loader);
@@ -74,7 +74,7 @@
     }
     {
       ObjectLock lock(klass);
-      klass->clinit_thread_id_ = self->GetThreadId();
+      klass->clinit_thread_id_ = self->GetId();
       // Add the newly loaded class to the loaded classes table.
       bool success = InsertClass(klass);
       if (!success) {
@@ -98,7 +98,7 @@
   if (!klass->IsLinked() && !klass->IsErroneous()) {
     ObjectLock lock(klass);
     // Check for circular dependencies between classes.
-    if (!klass->IsLinked() && klass->clinit_thread_id_ == self->GetThreadId()) {
+    if (!klass->IsLinked() && klass->clinit_thread_id_ == self->GetId()) {
       LG << "Recursive link";  // TODO: ClassCircularityError
       return NULL;
     }
@@ -198,7 +198,7 @@
   CHECK(klass->GetStatus() == Class::kStatusResolved ||
         klass->GetStatus() == Class::kStatusError);
 
-  Thread* self = Thread::Self();
+  Thread* self = Thread::Current();
 
   {
     ObjectLock lock(klass);
@@ -230,7 +230,7 @@
 
     while (klass->status_ == Class::kStatusInitializing) {
       // we caught somebody else in the act; was it us?
-      if (klass->clinit_thread_id_ == self->GetThreadId()) {
+      if (klass->clinit_thread_id_ == self->GetId()) {
         LG << "recursive <clinit>";
         return true;
       }
@@ -280,7 +280,7 @@
 
     assert(klass->status < CLASS_INITIALIZING);
 
-    klass->clinit_thread_id_ = self->GetThreadId();
+    klass->clinit_thread_id_ = self->GetId();
     klass->status_ = Class::kStatusInitializing;
   }
 
@@ -390,7 +390,7 @@
   // TODO: found2 == NULL
   // TODO: lookup found1 in initiating loader list
   if (found1 == NULL || found2 == NULL) {
-    Thread::Self()->ClearException();
+    Thread::Current()->ClearException();
     if (found1 == found2) {
       return true;
     } else {
@@ -996,7 +996,7 @@
     }
     dex_file->SetResolvedClass(resolved, class_idx);
   } else {
-    CHECK(Thread::Self()->IsExceptionPending());
+    CHECK(Thread::Current()->IsExceptionPending());
   }
   return resolved;
 }
diff --git a/src/runtime.h b/src/runtime.h
index 2afd9f0..495ab1c 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -3,6 +3,8 @@
 #ifndef ART_SRC_RUNTIME_H_
 #define ART_SRC_RUNTIME_H_
 
+#include "src/thread.h"
+
 namespace art {
 
 class Runtime {
@@ -11,10 +13,15 @@
   static void Shutdown();
 
   static void Compile(const char* filename);
+
+  void SetThreadList(ThreadList* thread_list) {
+    thread_list_ = thread_list;
+  }
+
+ private:
+  ThreadList* thread_list_;
 };
 
 }  // namespace art
 
-namespace r = art;
-
 #endif  // ART_SRC_RUNTIME_H_
diff --git a/src/thread.cc b/src/thread.cc
new file mode 100644
index 0000000..abd45db
--- /dev/null
+++ b/src/thread.cc
@@ -0,0 +1,104 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#include "src/thread.h"
+
+#include <algorithm>
+#include <list>
+#include <errno.h>
+#include <pthread.h>
+
+#include "src/runtime.h"
+
+namespace art {
+
+pthread_key_t Thread::pthread_key_self_;
+
+Mutex* Mutex::Create(const char* name) {
+  Mutex* mu = new Mutex(name);
+  int result = pthread_mutex_init(&mu->lock_impl_, NULL);
+  CHECK(result == 0);
+  return mu;
+}
+
+void Mutex::Lock() {
+  int result = pthread_mutex_lock(&lock_impl_);
+  CHECK_EQ(result, 0);
+  SetOwner(Thread::Current());
+}
+
+bool Mutex::TryLock() {
+  int result = pthread_mutex_lock(&lock_impl_);
+  if (result == EBUSY) {
+    return false;
+  } else {
+    CHECK_EQ(result, 0);
+    SetOwner(Thread::Current());
+    return true;
+  }
+}
+
+void Mutex::Unlock() {
+  CHECK(GetOwner() == Thread::Current());
+  int result = pthread_mutex_unlock(&lock_impl_);
+  CHECK_EQ(result, 0);
+  SetOwner(Thread::Current());
+}
+
+Thread* Thread::Create(const char* name) {
+  LOG(FATAL) << "Unimplemented";
+  return NULL;
+}
+
+static void ThreadExitCheck(void* arg) {
+  LG << "Thread exit check";
+}
+
+bool Thread::Init() {
+  // Allocate a TLS slot.
+  if (pthread_key_create(&Thread::pthread_key_self_, ThreadExitCheck) != 0) {
+    LOG(WARN) << "pthread_key_create failed";
+    return false;
+  }
+
+  // Double-check the TLS slot allocation.
+  if (pthread_getspecific(pthread_key_self_) != NULL) {
+    LOG(WARN) << "newly-created pthread TLS slot is not NULL";
+    return false;
+  }
+
+  // TODO: initialize other locks and condition variables
+
+  return true;
+}
+
+ThreadList::ThreadList() {
+  lock_ = Mutex::Create("ThreadList::Lock");
+}
+
+ThreadList::~ThreadList() {
+  // Make sure that all threads have exited and unregistered when we
+  // reach this point. This means that all daemon threads had been
+  // shutdown cleanly.
+  CHECK_EQ(list_.size(), 0);
+  delete lock_;
+  lock_ = NULL;
+}
+
+void ThreadList::Register(Thread* thread) {
+  MutexLock mu(lock_);
+  CHECK(find(list_.begin(), list_.end(), thread) == list_.end());
+  list_.push_front(thread);
+}
+
+void ThreadList::Unregister(Thread* thread) {
+  MutexLock mu(lock_);
+  CHECK(find(list_.begin(), list_.end(), thread) != list_.end());
+  list_.remove(thread);
+}
+
+void ThreadList::Init(Runtime* runtime) {
+  ThreadList* thread_list = new ThreadList();
+  runtime->SetThreadList(thread_list);
+}
+
+}  // namespace
diff --git a/src/thread.h b/src/thread.h
index b1bfb33..6cc2135 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -4,6 +4,9 @@
 #ifndef ART_SRC_THREAD_H_
 #define ART_SRC_THREAD_H_
 
+#include <list>
+#include <pthread.h>
+
 #include "src/globals.h"
 #include "src/logging.h"
 #include "src/macros.h"
@@ -11,22 +14,26 @@
 namespace art {
 
 class Object;
+class Runtime;
 class Thread;
+class ThreadList;
 
 class Mutex {
  public:
   virtual ~Mutex() {}
 
-  void Lock() {}
+  void Lock();
 
-  bool TryLock() { return true; }
+  bool TryLock();
 
-  void Unlock() {}
+  void Unlock();
 
   const char* GetName() { return name_; }
 
   Thread* GetOwner() { return owner_; }
 
+  static Mutex* Create(const char* name);
+
  public:  // TODO: protected
   explicit Mutex(const char* name) : name_(name), owner_(NULL) {}
 
@@ -37,6 +44,8 @@
 
   Thread* owner_;
 
+  pthread_mutex_t lock_impl_;
+
   DISALLOW_COPY_AND_ASSIGN(Mutex);
 };
 
@@ -53,13 +62,29 @@
 
 class Thread {
  public:
-  static Thread* Self() {
+  enum State {
+    kUnknown = -1,
+    kNew,
+    kRunnable,
+    kBlocked,
+    kWaiting,
+    kTimedWaiting,
+    kTerminated,
+  };
+
+  static Thread* Create(const char* name);
+
+  static Thread* Current() {
     static Thread self;
     return &self; // TODO
   }
 
-  uint32_t GetThreadId() {
-    return thread_id_;
+  uint32_t GetId() const {
+    return id_;
+  }
+
+  pid_t GetNativeId() const {
+    return native_id_;
   }
 
   bool IsExceptionPending() const {
@@ -80,17 +105,118 @@
     exception_ = NULL;
   }
 
+  void SetName(const char* name);
+
+  void Suspend();
+
+  bool IsSuspended();
+
+  void Resume();
+
+  static bool Init();
+
+  Thread* next_;
+
+  Thread* prev_;
+
+  State GetState() {
+    return state_;
+  }
+
+  void SetState(State new_state) {
+    state_ = new_state;
+  }
+
  private:
-  Thread() : thread_id_(1234), exception_(NULL) {}
+  Thread() : id_(1234), exception_(NULL) {}
   ~Thread() {}
 
-  uint32_t thread_id_;
+  State state_;
+
+  uint32_t id_;
+
+  pid_t native_id_;
+
+  pthread_t native_handle_;
 
   Object* exception_;
 
+  static pthread_key_t pthread_key_self_;
+
   DISALLOW_COPY_AND_ASSIGN(Thread);
 };
 
+class ThreadList {
+ public:
+  static const int kMaxThreadId = 0xFFFF;
+  static const int kMainThreadId = 1;
+
+  void Init(Runtime* runtime);
+
+  void Register(Thread* thread);
+
+  void Unregister(Thread* thread);
+
+  void SuspendAll();
+
+  void ResumeAll();
+
+  ~ThreadList();
+
+  void Lock() {
+    lock_->Lock();
+  }
+
+  void Unlock() {
+    lock_->Unlock();
+  };
+
+ private:
+  ThreadList();
+
+  std::list<Thread*> list_;
+
+  Mutex* lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadList);
+};
+
+class ThreadListLock {
+ public:
+  ThreadListLock(ThreadList* thread_list, Thread* current_thread)
+      : thread_list_(thread_list) {
+    if (current_thread == NULL) {  // try to get it from TLS
+      current_thread = Thread::Current();
+    }
+    Thread::State old_state;
+    if (current_thread != NULL) {
+      old_state = current_thread->GetState();
+      current_thread->SetState(Thread::kWaiting);  // TODO: VMWAIT
+    } else {
+      // happens during VM shutdown
+      old_state = Thread::kUnknown;  // TODO: something else
+    }
+    thread_list_->Lock();
+    if (current_thread != NULL) {
+      current_thread->SetState(old_state);
+    }
+  }
+
+  ~ThreadListLock() {
+    thread_list_->Unlock();
+  }
+
+  // Allocates
+  int AllocThreadId();
+
+  void FreeThreadId(int thread_id);
+
+ private:
+  ThreadList* thread_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadListLock);
+};
+
 }  // namespace art
 
 #endif  // ART_SRC_THREAD_H_