aboutsummaryrefslogtreecommitdiff
path: root/libc/bionic/pthread_cond.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libc/bionic/pthread_cond.cpp')
-rw-r--r--libc/bionic/pthread_cond.cpp23
1 files changed, 22 insertions, 1 deletions
diff --git a/libc/bionic/pthread_cond.cpp b/libc/bionic/pthread_cond.cpp
index e85706902..793dcd942 100644
--- a/libc/bionic/pthread_cond.cpp
+++ b/libc/bionic/pthread_cond.cpp
@@ -116,7 +116,8 @@ struct pthread_cond_internal_t {
}
#if defined(__LP64__)
- char __reserved[44];
+ atomic_uint waiters;
+ char __reserved[40];
#endif
};
@@ -141,6 +142,10 @@ int pthread_cond_init(pthread_cond_t* cond_interface, const pthread_condattr_t*
}
atomic_init(&cond->state, init_state);
+#if defined(__LP64__)
+ atomic_init(&cond->waiters, 0);
+#endif
+
return 0;
}
@@ -163,6 +168,12 @@ static int __pthread_cond_pulse(pthread_cond_internal_t* cond, int thread_count)
// not be called. That's why pthread_wait/signal pair can't be used as a method for memory
// synchronization. And it doesn't help even if we use any fence here.
+#if defined(__LP64__)
+ if (atomic_load_explicit(&cond->waiters, memory_order_relaxed) == 0) {
+ return 0;
+ }
+#endif
+
// The increase of value should leave flags alone, even if the value can overflows.
atomic_fetch_add_explicit(&cond->state, COND_COUNTER_STEP, memory_order_relaxed);
@@ -178,9 +189,19 @@ static int __pthread_cond_timedwait(pthread_cond_internal_t* cond, pthread_mutex
}
unsigned int old_state = atomic_load_explicit(&cond->state, memory_order_relaxed);
+
+#if defined(__LP64__)
+ atomic_fetch_add_explicit(&cond->waiters, 1, memory_order_relaxed);
+#endif
+
pthread_mutex_unlock(mutex);
int status = __futex_wait_ex(&cond->state, cond->process_shared(), old_state,
use_realtime_clock, abs_timeout_or_null);
+
+#if defined(__LP64__)
+ atomic_fetch_sub_explicit(&cond->waiters, 1, memory_order_relaxed);
+#endif
+
pthread_mutex_lock(mutex);
if (status == -ETIMEDOUT) {