More of the thread infrastructure.

We can now run managed code on multiple threads.

Change-Id: Ia4ce9c94602773db238c967c15194a6db780d12f
diff --git a/src/thread_list.cc b/src/thread_list.cc
index b0626c7..e3e4789 100644
--- a/src/thread_list.cc
+++ b/src/thread_list.cc
@@ -18,6 +18,8 @@
 
 namespace art {
 
+pthread_cond_t ThreadList::thread_start_cond_ = PTHREAD_COND_INITIALIZER;
+
 ThreadList::ThreadList() : lock_("ThreadList lock") {
 }
 
@@ -57,7 +59,7 @@
 void ThreadList::Unregister() {
   Thread* self = Thread::Current();
 
-  //LOG(INFO) << "ThreadList::Unregister() " << self;
+  //LOG(INFO) << "ThreadList::Unregister() " << *self;
   MutexLock mu(lock_);
 
   // Remove this thread from the list.
@@ -85,6 +87,59 @@
   }
 }
 
+/*
+ * Tell a new thread it's safe to start.
+ *
+ * We must hold the thread list lock before messing with another thread.
+ * In the general case we would also need to verify that the new thread was
+ * still in the thread list, but in our case the thread has not started
+ * executing user code and therefore has not had a chance to exit.
+ *
+ * We move it to kVmWait, and it then shifts itself to kRunning, which
+ * comes with a suspend-pending check. We do this after
+ */
+void ThreadList::SignalGo(Thread* child) {
+  Thread* self = Thread::Current();
+  CHECK(child != self);
+
+  {
+    MutexLock mu(lock_);
+
+    // We wait for the child to tell us that it's in the thread list.
+    while (child->GetState() != Thread::kStarting) {
+      pthread_cond_wait(&thread_start_cond_, lock_.GetImpl());
+    }
+  }
+
+  // If we switch out of runnable and then back in, we know there's no pending suspend.
+  self->SetState(Thread::kVmWait);
+  self->SetState(Thread::kRunnable);
+
+  // Tell the child that it's safe: it will see any future suspend request.
+  child->SetState(Thread::kVmWait);
+  pthread_cond_broadcast(&thread_start_cond_);
+}
+
+void ThreadList::WaitForGo() {
+  Thread* self = Thread::Current();
+  DCHECK(Contains(self));
+
+  MutexLock mu(lock_);
+
+  // Tell our parent that we're in the thread list.
+  self->SetState(Thread::kStarting);
+  pthread_cond_broadcast(&thread_start_cond_);
+
+  // Wait until our parent tells us there's no suspend still pending
+  // from before we were on the thread list.
+  while (self->GetState() != Thread::kVmWait) {
+    pthread_cond_wait(&thread_start_cond_, lock_.GetImpl());
+  }
+
+  // Enter the runnable state. We know that any pending suspend will affect us now.
+  self->SetState(Thread::kRunnable);
+}
+
 uint32_t ThreadList::AllocThreadId() {
   MutexLock mu(lock_);
   for (size_t i = 0; i < allocated_ids_.size(); ++i) {