Add a heap HWM to the Thread*, for compiled code.

Also fix a bug in thread detach, and implement the thread exit callback.

Destroy our pthread_mutex_t instances, and check for success. (This will
catch us deleting locked Mutex instances.)

Change-Id: I26cf8117b825234f6c790e0cf70b2c025a743f84
diff --git a/src/thread.cc b/src/thread.cc
index ae926ad..c771c5b 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -191,6 +191,13 @@
   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
@@ -203,7 +210,7 @@
   if (errno != 0) {
     PLOG(FATAL) << "pthread_mutexattr_settype failed";
   }
-  errno = pthread_mutex_init(&mu->lock_impl_, &debug_attributes);
+  errno = pthread_mutex_init(&mu->mutex_, &debug_attributes);
   if (errno != 0) {
     PLOG(FATAL) << "pthread_mutex_init failed";
   }
@@ -212,7 +219,7 @@
     PLOG(FATAL) << "pthread_mutexattr_destroy failed";
   }
 #else
-  errno = pthread_mutex_init(&mu->lock_impl_, NULL);
+  errno = pthread_mutex_init(&mu->mutex_, NULL);
   if (errno != 0) {
     PLOG(FATAL) << "pthread_mutex_init failed";
   }
@@ -221,7 +228,7 @@
 }
 
 void Mutex::Lock() {
-  int result = pthread_mutex_lock(&lock_impl_);
+  int result = pthread_mutex_lock(&mutex_);
   if (result != 0) {
     errno = result;
     PLOG(FATAL) << "pthread_mutex_lock failed";
@@ -229,7 +236,7 @@
 }
 
 bool Mutex::TryLock() {
-  int result = pthread_mutex_trylock(&lock_impl_);
+  int result = pthread_mutex_trylock(&mutex_);
   if (result == EBUSY) {
     return false;
   }
@@ -241,7 +248,7 @@
 }
 
 void Mutex::Unlock() {
-  int result = pthread_mutex_unlock(&lock_impl_);
+  int result = pthread_mutex_unlock(&mutex_);
   if (result != 0) {
     errno = result;
     PLOG(FATAL) << "pthread_mutex_unlock failed";
@@ -274,7 +281,7 @@
 Thread* Thread::Create(const Runtime* runtime) {
   UNIMPLEMENTED(FATAL) << "need to pass in a java.lang.Thread";
 
-  size_t stack_size = runtime->GetStackSize();
+  size_t stack_size = runtime->GetDefaultStackSize();
 
   Thread* new_thread = new Thread;
 
@@ -294,7 +301,7 @@
     PLOG(FATAL) << "pthread_attr_setstacksize(" << stack_size << ") failed";
   }
 
-  errno = pthread_create(&new_thread->handle_, &attr, ThreadStart, new_thread);
+  errno = pthread_create(&new_thread->pthread_, &attr, ThreadStart, new_thread);
   if (errno != 0) {
     PLOG(FATAL) << "pthread_create failed";
   }
@@ -314,9 +321,11 @@
   Thread* self = new Thread;
 
   self->tid_ = ::art::GetTid();
-  self->handle_ = pthread_self();
+  self->pthread_ = pthread_self();
   self->is_daemon_ = as_daemon;
 
+  self->InitStackHwm();
+
   self->state_ = kRunnable;
 
   SetThreadName(name);
@@ -350,15 +359,40 @@
   jboolean thread_is_daemon = as_daemon;
 
   jclass c = env->FindClass("java/lang/Thread");
-  LOG(INFO) << "java/lang/Thread=" << (void*)c;
   jmethodID mid = env->GetMethodID(c, "<init>", "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V");
-  LOG(INFO) << "java/lang/Thread.<init>=" << (void*)mid;
   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);
 }
 
+void Thread::InitStackHwm() {
+  pthread_attr_t attributes;
+  errno = pthread_getattr_np(pthread_, &attributes);
+  if (errno != 0) {
+    PLOG(FATAL) << "pthread_getattr_np failed";
+  }
+
+  // stack_base is the "lowest addressable byte" of the stack.
+  void* stack_base;
+  size_t stack_size;
+  errno = pthread_attr_getstack(&attributes, &stack_base, &stack_size);
+  if (errno != 0) {
+    PLOG(FATAL) << "pthread_attr_getstack failed";
+  }
+
+  const size_t kStackOverflowReservedBytes = 1024; // Space to throw a StackOverflowError in.
+  if (stack_size <= kStackOverflowReservedBytes) {
+    LOG(FATAL) << "attempt to attach a thread with a too-small stack (" << stack_size << " bytes)";
+  }
+  stack_hwm_ = reinterpret_cast<byte*>(stack_base) + stack_size - kStackOverflowReservedBytes;
+
+  errno = pthread_attr_destroy(&attributes);
+  if (errno != 0) {
+    PLOG(FATAL) << "pthread_attr_destroy failed";
+  }
+}
+
 void Thread::Dump(std::ostream& os) const {
   /*
    * Get the java.lang.Thread object.  This function gets called from
@@ -437,7 +471,7 @@
 
   int policy;
   sched_param sp;
-  errno = pthread_getschedparam(handle_, &policy, &sp);
+  errno = pthread_getschedparam(pthread_, &policy, &sp);
   if (errno != 0) {
     PLOG(FATAL) << "pthread_getschedparam failed";
   }
@@ -514,27 +548,24 @@
   os << "UNIMPLEMENTED: Thread::DumpStack\n";
 }
 
-static void ThreadExitCheck(void* arg) {
-  LG << "Thread exit check";
+void Thread::ThreadExitCallback(void* arg) {
+  Thread* self = reinterpret_cast<Thread*>(arg);
+  LOG(FATAL) << "Native thread exited without calling DetachCurrentThread: " << *self;
 }
 
-bool Thread::Startup() {
+void Thread::Startup() {
   // Allocate a TLS slot.
-  errno = pthread_key_create(&Thread::pthread_key_self_, ThreadExitCheck);
+  errno = pthread_key_create(&Thread::pthread_key_self_, Thread::ThreadExitCallback);
   if (errno != 0) {
-    PLOG(WARNING) << "pthread_key_create failed";
-    return false;
+    PLOG(FATAL) << "pthread_key_create failed";
   }
 
   // Double-check the TLS slot allocation.
   if (pthread_getspecific(pthread_key_self_) != NULL) {
-    LOG(WARNING) << "newly-created pthread TLS slot is not NULL";
-    return false;
+    LOG(FATAL) << "newly-created pthread TLS slot is not NULL";
   }
 
   // TODO: initialize other locks and condition variables
-
-  return true;
 }
 
 void Thread::Shutdown() {
@@ -939,21 +970,33 @@
 }
 
 void ThreadList::Register(Thread* thread) {
-  LOG(INFO) << "ThreadList::Register() " << *thread;
+  //LOG(INFO) << "ThreadList::Register() " << *thread;
   MutexLock mu(lock_);
   CHECK(!Contains(thread));
   list_.push_back(thread);
 }
 
 void ThreadList::Unregister() {
-  LOG(INFO) << "ThreadList::Unregister() " << *Thread::Current();
-  MutexLock mu(lock_);
   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 {