Throw OOME if pthread_create(3) fails.

This is how dalvik behaved, though we offer useful detail messages.

This patch also fixes a bug where we weren't actually including detail
messages in OOMEs (not just the pre-allocated one).

Change-Id: If6c8f47008a9bd058d9773f2f2e6e9a4f0d843e1
diff --git a/src/native/java_lang_Thread.cc b/src/native/java_lang_Thread.cc
index e009157..ed95a6c 100644
--- a/src/native/java_lang_Thread.cc
+++ b/src/native/java_lang_Thread.cc
@@ -32,18 +32,18 @@
   return Thread::Current()->Interrupted();
 }
 
-static jboolean Thread_isInterrupted(JNIEnv* env, jobject javaThread) {
+static jboolean Thread_isInterrupted(JNIEnv* env, jobject java_thread) {
   ScopedThreadListLock thread_list_lock;
-  Thread* thread = Thread::FromManagedThread(env, javaThread);
+  Thread* thread = Thread::FromManagedThread(env, java_thread);
   return (thread != NULL) ? thread->IsInterrupted() : JNI_FALSE;
 }
 
-static void Thread_nativeCreate(JNIEnv* env, jclass, jobject javaThread, jlong stackSize) {
-  Object* managedThread = Decode<Object*>(env, javaThread);
-  Thread::Create(managedThread, stackSize);
+static void Thread_nativeCreate(JNIEnv* env, jclass, jobject java_thread, jlong stack_size) {
+  Object* managedThread = Decode<Object*>(env, java_thread);
+  Thread::CreateNativeThread(managedThread, stack_size);
 }
 
-static jint Thread_nativeGetStatus(JNIEnv* env, jobject javaThread, jboolean hasBeenStarted) {
+static jint Thread_nativeGetStatus(JNIEnv* env, jobject java_thread, jboolean has_been_started) {
   // Ordinals from Java's Thread.State.
   const jint kJavaNew = 0;
   const jint kJavaRunnable = 1;
@@ -52,9 +52,9 @@
   const jint kJavaTimedWaiting = 4;
   const jint kJavaTerminated = 5;
 
-  ThreadState internal_thread_state = (hasBeenStarted ? kTerminated : kStarting);
+  ThreadState internal_thread_state = (has_been_started ? kTerminated : kStarting);
   ScopedThreadListLock thread_list_lock;
-  Thread* thread = Thread::FromManagedThread(env, javaThread);
+  Thread* thread = Thread::FromManagedThread(env, java_thread);
   if (thread != NULL) {
     internal_thread_state = thread->GetState();
   }
@@ -73,33 +73,33 @@
   return -1; // Unreachable.
 }
 
-static jboolean Thread_nativeHoldsLock(JNIEnv* env, jobject javaThread, jobject javaObject) {
-  Object* object = Decode<Object*>(env, javaObject);
+static jboolean Thread_nativeHoldsLock(JNIEnv* env, jobject java_thread, jobject java_object) {
+  Object* object = Decode<Object*>(env, java_object);
   if (object == NULL) {
     ScopedThreadStateChange tsc(Thread::Current(), kRunnable);
     Thread::Current()->ThrowNewException("Ljava/lang/NullPointerException;", "object == null");
     return JNI_FALSE;
   }
   ScopedThreadListLock thread_list_lock;
-  Thread* thread = Thread::FromManagedThread(env, javaThread);
+  Thread* thread = Thread::FromManagedThread(env, java_thread);
   return thread->HoldsLock(object);
 }
 
-static void Thread_nativeInterrupt(JNIEnv* env, jobject javaThread) {
+static void Thread_nativeInterrupt(JNIEnv* env, jobject java_thread) {
   ScopedThreadListLock thread_list_lock;
-  Thread* thread = Thread::FromManagedThread(env, javaThread);
+  Thread* thread = Thread::FromManagedThread(env, java_thread);
   if (thread != NULL) {
     thread->Interrupt();
   }
 }
 
-static void Thread_nativeSetName(JNIEnv* env, jobject javaThread, jstring javaName) {
+static void Thread_nativeSetName(JNIEnv* env, jobject java_thread, jstring java_name) {
   ScopedThreadListLock thread_list_lock;
-  Thread* thread = Thread::FromManagedThread(env, javaThread);
+  Thread* thread = Thread::FromManagedThread(env, java_thread);
   if (thread == NULL) {
     return;
   }
-  ScopedUtfChars name(env, javaName);
+  ScopedUtfChars name(env, java_name);
   if (name.c_str() == NULL) {
     return;
   }
@@ -107,15 +107,15 @@
 }
 
 /*
- * Alter the priority of the specified thread.  "newPriority" will range
+ * Alter the priority of the specified thread.  "new_priority" will range
  * from Thread.MIN_PRIORITY to Thread.MAX_PRIORITY (1-10), with "normal"
  * threads at Thread.NORM_PRIORITY (5).
  */
-static void Thread_nativeSetPriority(JNIEnv* env, jobject javaThread, jint newPriority) {
+static void Thread_nativeSetPriority(JNIEnv* env, jobject java_thread, jint new_priority) {
   ScopedThreadListLock thread_list_lock;
-  Thread* thread = Thread::FromManagedThread(env, javaThread);
+  Thread* thread = Thread::FromManagedThread(env, java_thread);
   if (thread != NULL) {
-    thread->SetNativePriority(newPriority);
+    thread->SetNativePriority(new_priority);
   }
 }
 
diff --git a/src/thread.cc b/src/thread.cc
index 60f0199..457de6a 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -205,7 +205,7 @@
   delete[] allocated_signal_stack;
 }
 
-void Thread::Create(Object* peer, size_t stack_size) {
+void Thread::CreateNativeThread(Object* peer, size_t stack_size) {
   CHECK(peer != NULL);
 
   stack_size = FixStackSize(stack_size);
@@ -217,6 +217,7 @@
   // and know that we're not racing to assign it.
   SetVmData(peer, native_thread);
 
+  int pthread_create_result = 0;
   {
     ScopedThreadStateChange tsc(Thread::Current(), kVmWait);
     pthread_t new_pthread;
@@ -224,10 +225,21 @@
     CHECK_PTHREAD_CALL(pthread_attr_init, (&attr), "new thread");
     CHECK_PTHREAD_CALL(pthread_attr_setdetachstate, (&attr, PTHREAD_CREATE_DETACHED), "PTHREAD_CREATE_DETACHED");
     CHECK_PTHREAD_CALL(pthread_attr_setstacksize, (&attr, stack_size), stack_size);
-    CHECK_PTHREAD_CALL(pthread_create, (&new_pthread, &attr, Thread::CreateCallback, native_thread), "new thread");
+    pthread_create_result = pthread_create(&new_pthread, &attr, Thread::CreateCallback, native_thread);
     CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attr), "new thread");
   }
 
+  if (pthread_create_result != 0) {
+    // pthread_create(3) failed, so clean up.
+    SetVmData(peer, 0);
+    delete native_thread;
+
+    std::string msg(StringPrintf("pthread_create (%s stack) failed: %s",
+                                 PrettySize(stack_size).c_str(), strerror(pthread_create_result)));
+    Thread::Current()->ThrowOutOfMemoryError(msg.c_str());
+    return;
+  }
+
   // Let the child know when it's safe to start running.
   Runtime::Current()->GetThreadList()->SignalGo(native_thread);
 }
@@ -1468,7 +1480,7 @@
       msg, (throwing_OutOfMemoryError_ ? " (recursive case)" : ""));
   if (!throwing_OutOfMemoryError_) {
     throwing_OutOfMemoryError_ = true;
-    ThrowNewException("Ljava/lang/OutOfMemoryError;", NULL);
+    ThrowNewException("Ljava/lang/OutOfMemoryError;", msg);
   } else {
     Dump(LOG(ERROR)); // The pre-allocated OOME has no stack, so help out and log one.
     SetException(Runtime::Current()->GetPreAllocatedOutOfMemoryError());
diff --git a/src/thread.h b/src/thread.h
index 310f629..c674ded 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -102,7 +102,7 @@
 
   // Creates a new native thread corresponding to the given managed peer.
   // Used to implement Thread.start.
-  static void Create(Object* peer, size_t stack_size);
+  static void CreateNativeThread(Object* peer, size_t stack_size);
 
   // Attaches the calling native thread to the runtime, returning the new native peer.
   // Used to implement JNI AttachCurrentThread and AttachCurrentThreadAsDaemon calls.