]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android-sdk/platform-bionic.git/blobdiff - libc/bionic/pthread_join.cpp
Use mmap to create the pthread_internal_t
[android-sdk/platform-bionic.git] / libc / bionic / pthread_join.cpp
index e6acc34cec152e04a0444d27f2400313c4e3bc95..e3350efd35169b8efbd3523bf72323d0a41c0928 100644 (file)
 
 #include <errno.h>
 
+#include "private/bionic_futex.h"
 #include "pthread_accessor.h"
 
-int pthread_join(pthread_t t, void ** ret_val) {
+int pthread_join(pthread_t t, void** return_value) {
   if (t == pthread_self()) {
     return EDEADLK;
   }
 
-  pthread_accessor thread(t);
-  if (thread.get() == NULL) {
+  pid_t tid;
+  volatile int* tid_ptr;
+  {
+    pthread_accessor thread(t);
+    if (thread.get() == NULL) {
       return ESRCH;
-  }
+    }
 
-  if (thread->attr.flags & PTHREAD_ATTR_FLAG_DETACHED) {
-    return EINVAL;
-  }
+    if ((thread->attr.flags & PTHREAD_ATTR_FLAG_DETACHED) != 0) {
+      return EINVAL;
+    }
 
-  // Wait for thread death when needed.
+    if ((thread->attr.flags & PTHREAD_ATTR_FLAG_JOINED) != 0) {
+      return EINVAL;
+    }
 
-  // If the 'join_count' is negative, this is a 'zombie' thread that
-  // is already dead and without stack/TLS. Otherwise, we need to increment 'join-count'
-  // and wait to be signaled
-  int count = thread->join_count;
-  if (count >= 0) {
-    thread->join_count += 1;
-    pthread_cond_wait(&thread->join_cond, &gThreadListLock);
-    count = --thread->join_count;
+    // Okay, looks like we can signal our intention to join.
+    thread->attr.flags |= PTHREAD_ATTR_FLAG_JOINED;
+    tid = thread->tid;
+    tid_ptr = &thread->tid;
   }
-  if (ret_val) {
-    *ret_val = thread->return_value;
+
+  // We set the PTHREAD_ATTR_FLAG_JOINED flag with the lock held,
+  // so no one is going to remove this thread except us.
+
+  // Wait for the thread to actually exit, if it hasn't already.
+  while (*tid_ptr != 0) {
+    __futex_wait(tid_ptr, tid, NULL);
   }
 
-  // Remove thread from thread list when we're the last joiner or when the
-  // thread was already a zombie.
-  if (count <= 0) {
-    _pthread_internal_remove_locked(thread.get());
+  // Take the lock again so we can pull the thread's return value
+  // and remove the thread from the list.
+  pthread_accessor thread(t);
+
+  if (return_value) {
+    *return_value = thread->return_value;
   }
+
+  _pthread_internal_remove_locked(thread.get(), true);
   return 0;
 }