Skip to content

Commit be4cbc7

Browse files
committed
add better rwlock downgrade test cases
1 parent 78d5f2a commit be4cbc7

File tree

1 file changed

+80
-2
lines changed

1 file changed

+80
-2
lines changed

library/std/src/sync/rwlock/tests.rs

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use crate::sync::atomic::{AtomicUsize, Ordering};
22
use crate::sync::mpsc::channel;
33
use crate::sync::{
4-
Arc, MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard, RwLockWriteGuard,
5-
TryLockError,
4+
Arc, Barrier, MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard,
5+
RwLockWriteGuard, TryLockError,
66
};
77
use crate::thread;
88
use rand::Rng;
@@ -504,3 +504,81 @@ fn test_downgrade_basic() {
504504
let write_guard = r.write().unwrap();
505505
let _read_guard = RwLockWriteGuard::downgrade(write_guard);
506506
}
507+
508+
#[test]
509+
fn test_downgrade_frob() {
510+
const N: u32 = 10;
511+
const M: usize = if cfg!(miri) { 100 } else { 1000 };
512+
513+
let r = Arc::new(RwLock::new(()));
514+
515+
let (tx, rx) = channel::<()>();
516+
for _ in 0..N {
517+
let tx = tx.clone();
518+
let r = r.clone();
519+
thread::spawn(move || {
520+
let mut rng = crate::test_helpers::test_rng();
521+
for _ in 0..M {
522+
if rng.gen_bool(1.0 / (N as f64)) {
523+
drop(RwLockWriteGuard::downgrade(r.write().unwrap()));
524+
} else {
525+
drop(r.read().unwrap());
526+
}
527+
}
528+
drop(tx);
529+
});
530+
}
531+
drop(tx);
532+
let _ = rx.recv();
533+
}
534+
535+
#[test]
536+
fn test_downgrade_readers() {
537+
const R: usize = 16;
538+
const N: usize = 1000;
539+
540+
let r = Arc::new(RwLock::new(0));
541+
let b = Arc::new(Barrier::new(R + 1));
542+
543+
// Create the writing thread.
544+
let r_writer = r.clone();
545+
let b_writer = b.clone();
546+
thread::spawn(move || {
547+
for i in 0..N {
548+
let mut write_guard = r_writer.write().unwrap();
549+
*write_guard = i;
550+
551+
let read_guard = RwLockWriteGuard::downgrade(write_guard);
552+
assert_eq!(*read_guard, i);
553+
554+
// Wait for all readers to observe the new value.
555+
b_writer.wait();
556+
}
557+
});
558+
559+
for _ in 0..R {
560+
let r = r.clone();
561+
let b = b.clone();
562+
thread::spawn(move || {
563+
// Every reader thread needs to observe every value up to `N`.
564+
for i in 0..N {
565+
let read_guard = r.read().unwrap();
566+
assert_eq!(*read_guard, i);
567+
drop(read_guard);
568+
569+
// Wait for everyone to read and for the writer to change the value again.
570+
b.wait();
571+
// Spin until the writer has changed the value.
572+
573+
loop {
574+
let read_guard = r.read().unwrap();
575+
assert!(*read_guard >= i);
576+
577+
if *read_guard > i {
578+
break;
579+
}
580+
}
581+
}
582+
});
583+
}
584+
}

0 commit comments

Comments
 (0)