Add memory barriers to pthread_once.
The implementation was using a double-checked locking approach that
could break on SMP.
In addition to the barriers I also switched to a volatile pointer. I
don't think this will matter unless gcc can conclude that _normal_lock
can't affect *once_control, but I figured it was better to be safe.
(It seems to have no impact whatsoever on the generated code.)
Bug 3022795.
Change-Id: Ib91da25d57ff5bee4288526e39d457153ef6aacd
diff --git a/libc/bionic/pthread.c b/libc/bionic/pthread.c
index dd8d758..a195018 100644
--- a/libc/bionic/pthread.c
+++ b/libc/bionic/pthread.c
@@ -1886,12 +1886,16 @@
int pthread_once( pthread_once_t* once_control, void (*init_routine)(void) )
{
static pthread_mutex_t once_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
+ volatile pthread_once_t* ocptr = once_control;
- if (*once_control == PTHREAD_ONCE_INIT) {
+ pthread_once_t tmp = *ocptr;
+ ANDROID_MEMBAR_FULL();
+ if (tmp == PTHREAD_ONCE_INIT) {
pthread_mutex_lock( &once_lock );
- if (*once_control == PTHREAD_ONCE_INIT) {
+ if (*ocptr == PTHREAD_ONCE_INIT) {
(*init_routine)();
- *once_control = ~PTHREAD_ONCE_INIT;
+ ANDROID_MEMBAR_FULL();
+ *ocptr = ~PTHREAD_ONCE_INIT;
}
pthread_mutex_unlock( &once_lock );
}