Handles spurious wake-ups in pthread_join()
Removed 'join_count' from pthread_internal_t and switched to using the flag
PTHREAD_ATTR_FLAG_JOINED to indicate if a thread is being joined. Combined with
a switch to a while loop in pthread_join, this fixes spurious wake-ups but
prevents a thread from being joined multiple times. This is fine for
two reasons:
1) The pthread_join specification allows for undefined behavior when multiple
threads try to join a single thread.
2) There is no thread safe way to allow multiple threads to join a single
thread with the pthread interface. The second thread calling pthread_join
could be pre-empted until the thread is destroyed and its handle reused for
a different thread. Therefore multi-join is always an error.
Bug: https://code.google.com/p/android/issues/detail?id=52255
Change-Id: I8b6784d47620ffdcdbfb14524e7402e21d46c5f7
diff --git a/libc/bionic/pthread.c b/libc/bionic/pthread.c
index e30fa9d..fb14097 100644
--- a/libc/bionic/pthread.c
+++ b/libc/bionic/pthread.c
@@ -130,23 +130,13 @@
thread->tls = NULL;
}
- /* the join_count field is used to store the number of threads waiting for
- * the termination of this thread with pthread_join(),
- *
- * if it is positive we need to signal the waiters, and we do not touch
- * the count (it will be decremented by the waiters, the last one will
- * also remove/free the thread structure
- *
- * if it is zero, we set the count value to -1 to indicate that the
- * thread is in 'zombie' state: it has stopped executing, and its stack
- * is gone (as well as its TLS area). when another thread calls pthread_join()
- * on it, it will immediately free the thread and return.
- */
+ /* Indicate that the thread has exited for joining threads. */
+ thread->attr.flags |= PTHREAD_ATTR_FLAG_ZOMBIE;
thread->return_value = retval;
- if (thread->join_count > 0) {
- pthread_cond_broadcast(&thread->join_cond);
- } else {
- thread->join_count = -1; /* zombie thread */
+
+ /* Signal the joining thread if present. */
+ if (thread->attr.flags & PTHREAD_ATTR_FLAG_JOINED) {
+ pthread_cond_signal(&thread->join_cond);
}
}
pthread_mutex_unlock(&gThreadListLock);