From 3c505266299bfe97241adf6dd337899b14d4aa94 Mon Sep 17 00:00:00 2001 From: Yifan Zhu Date: Thu, 4 Jun 2026 09:38:06 -0700 Subject: [PATCH 1/2] [libc][rwlock] fix the race condition in waiter queue --- libc/src/__support/threads/raw_rwlock.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libc/src/__support/threads/raw_rwlock.h b/libc/src/__support/threads/raw_rwlock.h index 9bc1b88cabd69..e5b89c2ef7e6f 100644 --- a/libc/src/__support/threads/raw_rwlock.h +++ b/libc/src/__support/threads/raw_rwlock.h @@ -75,11 +75,11 @@ class WaitingQueue final : private RawMutex { else return queue.pending_writers; } - template LIBC_INLINE FutexWordType &serialization() { + template LIBC_INLINE Futex &serialization() { if constexpr (role == Role::Reader) - return queue.reader_serialization.val; + return queue.reader_serialization; else - return queue.writer_serialization.val; + return queue.writer_serialization; } friend WaitingQueue; }; @@ -391,8 +391,8 @@ class RawRwLock { // sleep on the futex, we can avoid such waiting. old = RwState::fetch_set_pending_bit(state, cpp::MemoryOrder::RELAXED); - // no need to use atomic since it is already protected by the mutex. - serial_number = guard.serialization(); + // relaxed atomic since it is already protected by the mutex. + serial_number = guard.serialization().load(cpp::MemoryOrder::RELAXED); } // Phase 6: do futex wait until the lock is available or timeout is @@ -437,10 +437,10 @@ class RawRwLock { { WaitingQueue::Guard guard = queue.acquire(is_pshared); if (guard.pending_count() != 0) { - guard.serialization()++; + guard.serialization().fetch_add(1, cpp::MemoryOrder::RELEASE); status = WakeTarget::Writers; } else if (guard.pending_count() != 0) { - guard.serialization()++; + guard.serialization().fetch_add(1, cpp::MemoryOrder::RELEASE); status = WakeTarget::Readers; } else { status = WakeTarget::None; From de29f595e6234fc6858382b623482e408292cbf8 Mon Sep 17 00:00:00 2001 From: Yifan Zhu Date: Thu, 4 Jun 2026 09:43:18 -0700 Subject: [PATCH 2/2] fmt --- libc/src/__support/threads/raw_rwlock.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libc/src/__support/threads/raw_rwlock.h b/libc/src/__support/threads/raw_rwlock.h index e5b89c2ef7e6f..1b0bba9c72675 100644 --- a/libc/src/__support/threads/raw_rwlock.h +++ b/libc/src/__support/threads/raw_rwlock.h @@ -392,7 +392,8 @@ class RawRwLock { old = RwState::fetch_set_pending_bit(state, cpp::MemoryOrder::RELAXED); // relaxed atomic since it is already protected by the mutex. - serial_number = guard.serialization().load(cpp::MemoryOrder::RELAXED); + serial_number = + guard.serialization().load(cpp::MemoryOrder::RELAXED); } // Phase 6: do futex wait until the lock is available or timeout is @@ -437,10 +438,12 @@ class RawRwLock { { WaitingQueue::Guard guard = queue.acquire(is_pshared); if (guard.pending_count() != 0) { - guard.serialization().fetch_add(1, cpp::MemoryOrder::RELEASE); + guard.serialization().fetch_add( + 1, cpp::MemoryOrder::RELEASE); status = WakeTarget::Writers; } else if (guard.pending_count() != 0) { - guard.serialization().fetch_add(1, cpp::MemoryOrder::RELEASE); + guard.serialization().fetch_add( + 1, cpp::MemoryOrder::RELEASE); status = WakeTarget::Readers; } else { status = WakeTarget::None;