Skip to content

Commit b0c6839

Browse files
committed
added tests
1 parent de56576 commit b0c6839

File tree

1 file changed

+136
-23
lines changed

1 file changed

+136
-23
lines changed

Diff for: futures-util/src/lock/rwlock.rs

+136-23
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use std::cell::UnsafeCell;
55
use std::fmt;
66
use std::ops::{Deref, DerefMut};
77
use std::pin::Pin;
8-
use std::sync::RwLock as StdRwLock;
98
use std::sync::atomic::{AtomicUsize, Ordering};
9+
use std::sync::RwLock as StdRwLock;
1010

1111
#[allow(clippy::identity_op)]
1212
const PHASE: usize = 1 << 0;
@@ -43,6 +43,12 @@ impl AtomicState {
4343
self.read.out.fetch_add(ONE_READER, Ordering::SeqCst)
4444
}
4545

46+
#[cfg(test)]
47+
#[inline]
48+
fn waiting_readers(&self) -> usize {
49+
self.read.ins.load(Ordering::Relaxed)
50+
}
51+
4652
#[inline]
4753
fn waiting_writers(&self) -> usize {
4854
self.write.ins.load(Ordering::Relaxed)
@@ -98,7 +104,25 @@ pub struct RwLock<T: ?Sized> {
98104

99105
impl<T: ?Sized> fmt::Debug for RwLock<T> {
100106
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101-
f.debug_struct("RwLock").finish()
107+
f.debug_struct("RwLock")
108+
.field("phase", &format!("{:#b}", self.atomic.phase()))
109+
.field(
110+
"read_ins",
111+
&format!("{:#b}", self.atomic.read.ins.load(Ordering::Relaxed)),
112+
)
113+
.field(
114+
"read_out",
115+
&format!("{:#b}", self.atomic.read.out.load(Ordering::Relaxed)),
116+
)
117+
.field(
118+
"write_ins",
119+
&format!("{:#b}", self.atomic.write.ins.load(Ordering::Relaxed)),
120+
)
121+
.field(
122+
"write_out",
123+
&format!("{:#b}", self.atomic.write.out.load(Ordering::Relaxed)),
124+
)
125+
.finish()
102126
}
103127
}
104128

@@ -125,15 +149,6 @@ impl<T> RwLock<T> {
125149
}
126150

127151
/// Consumes the read-write lock, returning the underlying data.
128-
///
129-
/// # Examples
130-
///
131-
/// ```
132-
/// use futures::lock::RwLock;
133-
///
134-
/// let rwlock = RwLock::new(0);
135-
/// assert_eq!(rwlock.into_inner(), 0);
136-
/// ```
137152
pub fn into_inner(self) -> T {
138153
self.value.into_inner()
139154
}
@@ -216,18 +231,6 @@ impl<T: ?Sized> RwLock<T> {
216231
///
217232
/// Since this call borrows the lock mutably, no actual locking needs to
218233
/// take place -- the mutable borrow statically guarantees no locks exist.
219-
///
220-
/// # Examples
221-
///
222-
/// ```
223-
/// # futures::executor::block_on(async {
224-
/// use futures::lock::RwLock;
225-
///
226-
/// let mut rwlock = RwLock::new(0);
227-
/// *rwlock.get_mut() = 10;
228-
/// assert_eq!(*rwlock.read().await, 10);
229-
/// # });
230-
/// ```
231234
pub fn get_mut(&mut self) -> &mut T {
232235
unsafe { &mut *self.value.get() }
233236
}
@@ -518,3 +521,113 @@ unsafe impl<T: ?Sized + Sync> Sync for RwLockReadGuard<'_, T> {}
518521

519522
unsafe impl<T: ?Sized + Send> Send for RwLockWriteGuard<'_, T> {}
520523
unsafe impl<T: ?Sized + Sync> Sync for RwLockWriteGuard<'_, T> {}
524+
525+
#[cfg(test)]
526+
use futures::executor::{block_on, ThreadPool};
527+
#[cfg(test)]
528+
use futures::join;
529+
530+
#[test]
531+
fn single_read() {
532+
block_on(async {
533+
let rwlock = RwLock::new(0);
534+
assert_eq!(*rwlock.read().await, 0);
535+
})
536+
}
537+
538+
#[test]
539+
fn multiple_reads() {
540+
let pool = ThreadPool::new().unwrap();
541+
pool.spawn_ok(async {
542+
let rwlock = RwLock::new(0);
543+
join!(rwlock.read(), rwlock.read(), rwlock.read());
544+
})
545+
}
546+
547+
#[test]
548+
fn single_thread_multiple_reads() {
549+
block_on(async {
550+
let rwlock = RwLock::new(0);
551+
let guard1 = rwlock.read().await;
552+
let guard2 = rwlock.read().await;
553+
assert_eq!(*guard1, *guard2);
554+
})
555+
}
556+
557+
#[test]
558+
fn single_write() {
559+
block_on(async {
560+
let rwlock = RwLock::new(0);
561+
*rwlock.write().await += 1;
562+
assert_eq!(*rwlock.read().await, 1);
563+
})
564+
}
565+
566+
#[test]
567+
fn write_among_two_reads() {
568+
let pool = ThreadPool::new().unwrap();
569+
pool.spawn_ok(async {
570+
let rwlock = RwLock::new(0);
571+
join!(rwlock.write(), rwlock.read(), rwlock.read());
572+
})
573+
}
574+
575+
#[test]
576+
fn two_writes_among_two_reads() {
577+
let pool = ThreadPool::new().unwrap();
578+
pool.spawn_ok(async {
579+
let rwlock = RwLock::new(0);
580+
join!(rwlock.write(), rwlock.read(), rwlock.write(), rwlock.read());
581+
})
582+
}
583+
584+
#[test]
585+
fn read_state_progression() {
586+
block_on(async {
587+
let rwlock = RwLock::new(0);
588+
let guard1 = rwlock.read().await;
589+
assert_eq!(rwlock.atomic.waiting_readers(), 1 << 2);
590+
let guard2 = rwlock.read().await;
591+
assert_eq!(rwlock.atomic.waiting_readers(), 2 << 2);
592+
assert_eq!(rwlock.atomic.finished_readers(), 0);
593+
drop(guard1);
594+
drop(guard2);
595+
assert_eq!(rwlock.atomic.finished_readers(), 2 << 2);
596+
})
597+
}
598+
599+
#[test]
600+
fn write_state_progression() {
601+
block_on(async {
602+
let rwlock = RwLock::new(0);
603+
let guard1 = rwlock.write().await;
604+
assert_eq!(rwlock.atomic.waiting_writers(), 1);
605+
assert_eq!(rwlock.atomic.phase(), 2);
606+
drop(guard1);
607+
assert_eq!(rwlock.atomic.phase(), 0);
608+
let guard2 = rwlock.write().await;
609+
assert_eq!(rwlock.atomic.waiting_writers(), 2);
610+
assert_eq!(rwlock.atomic.phase(), 3);
611+
drop(guard2);
612+
assert_eq!(rwlock.atomic.finished_writers(), 2);
613+
})
614+
}
615+
616+
#[test]
617+
fn try_read_and_write() {
618+
let rwlock = RwLock::new(0);
619+
let mut guard = rwlock.try_write().unwrap();
620+
assert!(rwlock.try_read().is_none());
621+
assert_eq!(rwlock.atomic.phase(), 1);
622+
*guard += 1;
623+
drop(guard);
624+
let guard = rwlock.try_read().unwrap();
625+
assert!(rwlock.try_write().is_none());
626+
assert_eq!(*guard, 1);
627+
drop(guard);
628+
assert_eq!(rwlock.atomic.phase(), 0);
629+
assert_eq!(rwlock.atomic.waiting_readers(), 1 << 2);
630+
assert_eq!(rwlock.atomic.finished_readers(), 1 << 2);
631+
assert_eq!(rwlock.atomic.waiting_writers(), 1);
632+
assert_eq!(rwlock.atomic.finished_writers(), 1);
633+
}

0 commit comments

Comments
 (0)