Skip to content

Commit 4ad7ee5

Browse files
committed
fixed missing state variable for waiting readers
1 parent 1430b05 commit 4ad7ee5

File tree

1 file changed

+17
-9
lines changed

1 file changed

+17
-9
lines changed

futures-util/src/lock/rwlock.rs

+17-9
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ impl<T: ?Sized> fmt::Debug for RwLock<T> {
2222
let state = self.state.load(Ordering::SeqCst);
2323
f.debug_struct("RwLock")
2424
.field("is_locked", &((state & IS_LOCKED) != 0))
25-
.field("has_waiters", &((state & HAS_WAITERS) != 0))
26-
.field("readers", &((state & READ_COUNT_MASK) >> 2))
25+
.field("has_writers", &((state & HAS_WRITERS) != 0))
26+
.field("has_readers", &((state & HAS_READERS) != 0))
27+
.field("active_readers", &((state & READ_COUNT_MASK) >> 3))
2728
.finish()
2829
}
2930
}
@@ -51,10 +52,11 @@ impl Waiter {
5152

5253
#[allow(clippy::identity_op)]
5354
const IS_LOCKED: usize = 1 << 0;
54-
const HAS_WAITERS: usize = 1 << 1;
55-
const ONE_READER: usize = 1 << 2;
55+
const HAS_WRITERS: usize = 1 << 1;
56+
const HAS_READERS: usize = 1 << 2;
57+
const ONE_READER: usize = 1 << 3;
5658
const READ_COUNT_MASK: usize = !(ONE_READER - 1);
57-
const MAX_READERS: usize = usize::max_value() >> 2;
59+
const MAX_READERS: usize = usize::max_value() >> 3;
5860

5961
impl<T> RwLock<T> {
6062
/// Creates a new futures-aware read-write lock.
@@ -170,6 +172,9 @@ impl<T: ?Sized> RwLock<T> {
170172
// No need to check whether another waiter needs to be
171173
// woken up since no other readers depend on this.
172174
readers.remove(wait_key);
175+
if readers.is_empty() {
176+
self.state.fetch_and(!HAS_READERS, Ordering::Relaxed);
177+
}
173178
}
174179
}
175180

@@ -190,7 +195,7 @@ impl<T: ?Sized> RwLock<T> {
190195
}
191196
}
192197
if writers.is_empty() {
193-
self.state.fetch_and(!HAS_WAITERS, Ordering::Relaxed);
198+
self.state.fetch_and(!HAS_WRITERS, Ordering::Relaxed);
194199
}
195200
}
196201
}
@@ -248,6 +253,9 @@ impl<'a, T: ?Sized> Future for RwLockReadFuture<'a, T> {
248253
let mut readers = rwlock.read_waiters.lock().unwrap();
249254
if self.wait_key == WAIT_KEY_NONE {
250255
self.wait_key = readers.insert(Waiter::Waiting(cx.waker().clone()));
256+
if readers.len() == 1 {
257+
rwlock.state.fetch_or(HAS_READERS, Ordering::Relaxed);
258+
}
251259
} else {
252260
readers[self.wait_key].register(cx.waker());
253261
}
@@ -322,7 +330,7 @@ impl<'a, T: ?Sized> Future for RwLockWriteFuture<'a, T> {
322330
if self.wait_key == WAIT_KEY_NONE {
323331
self.wait_key = writers.insert(Waiter::Waiting(cx.waker().clone()));
324332
if writers.len() == 1 {
325-
rwlock.state.fetch_or(HAS_WAITERS, Ordering::Relaxed);
333+
rwlock.state.fetch_or(HAS_WRITERS, Ordering::Relaxed);
326334
}
327335
} else {
328336
writers[self.wait_key].register(cx.waker());
@@ -373,7 +381,7 @@ impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLockReadGuard<'_, T> {
373381
impl<T: ?Sized> Drop for RwLockReadGuard<'_, T> {
374382
fn drop(&mut self) {
375383
let old_state = self.rwlock.state.fetch_sub(ONE_READER, Ordering::SeqCst);
376-
if old_state & READ_COUNT_MASK == ONE_READER && old_state & HAS_WAITERS != 0 {
384+
if old_state & READ_COUNT_MASK == ONE_READER && old_state & HAS_WRITERS != 0 {
377385
let mut writers = self.rwlock.write_waiters.lock().unwrap();
378386
if let Some((_, waiter)) = writers.iter_mut().next() {
379387
waiter.wake();
@@ -414,7 +422,7 @@ impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLockWriteGuard<'_, T> {
414422
impl<T: ?Sized> Drop for RwLockWriteGuard<'_, T> {
415423
fn drop(&mut self) {
416424
let old_state = self.rwlock.state.fetch_and(!IS_LOCKED, Ordering::AcqRel);
417-
match (old_state & HAS_WAITERS, old_state & READ_COUNT_MASK) {
425+
match (old_state & HAS_WRITERS, old_state & HAS_READERS) {
418426
(0, 0) => {}
419427
(0, _) => {
420428
let mut readers = self.rwlock.read_waiters.lock().unwrap();

0 commit comments

Comments
 (0)