@@ -591,29 +591,34 @@ fn test_downgrade_readers() {
591
591
}
592
592
}
593
593
594
+ #[ test]
594
595
fn test_downgrade_atomic ( ) {
596
+ // Spawns many evil writer threads that will try and write to the locked value before the
597
+ // intial writer who has the exlusive lock can read after it downgrades.
598
+ // If the `RwLock` behaves correctly, then the initial writer should read the value it wrote
599
+ // itself as no other thread should get in front of it.
600
+
595
601
// The number of evil writer threads.
596
602
const W : usize = 1024 ;
597
603
let rw = Arc :: new ( RwLock :: new ( 0i32 ) ) ;
598
604
599
605
// Put the lock in write mode, making all future threads trying to access this go to sleep.
600
606
let mut main_write_guard = rw. write ( ) . unwrap ( ) ;
601
607
602
- let mut handles = Vec :: with_capacity ( W ) ;
603
-
604
- for _ in 0 ..W {
605
- let w = rw. clone ( ) ;
606
- let evil_handle = thread:: spawn ( move || {
607
- // Will go to sleep since the main thread initially has the write lock.
608
- let mut evil_guard = w. write ( ) . unwrap ( ) ;
609
- * evil_guard += 1 ;
610
- } ) ;
611
-
612
- handles. push ( evil_handle) ;
613
- }
608
+ // Spawn all of the evil writer threads.
609
+ let handles: Vec < _ > = ( 0 ..W )
610
+ . map ( |_| {
611
+ let w = rw. clone ( ) ;
612
+ thread:: spawn ( move || {
613
+ // Will go to sleep since the main thread initially has the write lock.
614
+ let mut evil_guard = w. write ( ) . unwrap ( ) ;
615
+ * evil_guard += 1 ;
616
+ } )
617
+ } )
618
+ . collect ( ) ;
614
619
615
620
// Wait for a good amount of time so that evil threads go to sleep.
616
- // Note that this is not striclty necessary.
621
+ // ( Note that this is not striclty necessary...)
617
622
let eternity = time:: Duration :: from_secs ( 1 ) ;
618
623
thread:: sleep ( eternity) ;
619
624
@@ -627,112 +632,12 @@ fn test_downgrade_atomic() {
627
632
// read and change the value to be non-negative.
628
633
assert_eq ! ( * main_read_guard, -1 , "`downgrade` was not atomic" ) ;
629
634
635
+ // Clean up everything now
630
636
drop ( main_read_guard) ;
631
-
632
637
for handle in handles {
633
638
handle. join ( ) . unwrap ( ) ;
634
639
}
635
640
636
641
let final_check = rw. read ( ) . unwrap ( ) ;
637
642
assert_eq ! ( * final_check, W as i32 - 1 ) ;
638
643
}
639
-
640
- #[ test]
641
- #[ ignore]
642
- fn test_downgrade_atomic_many ( ) {
643
- for _ in 0 ..10 {
644
- test_downgrade_atomic ( ) ;
645
- }
646
- }
647
-
648
- #[ test]
649
- #[ ignore]
650
- fn test_downgrade_wake_readers ( ) {
651
- // The number of reader threads.
652
- const R : usize = 16 ;
653
-
654
- let r = Arc :: new ( RwLock :: new ( 0 ) ) ;
655
- // The number of reader threads that have observed the correct value.
656
- let observers = Arc :: new ( AtomicUsize :: new ( 0 ) ) ;
657
-
658
- let w = r. clone ( ) ;
659
- let mut main_write_guard = w. write ( ) . unwrap ( ) ;
660
-
661
- // While the current thread is holding the write lock, spawn several reader threads and an evil
662
- // writer thread.
663
- // Each of the threads will attempt to read the `RwLock` and go to sleep because we have the
664
- // write lock.
665
- // We need at least 1 reader thread to observe what the main thread writes, otherwise that means
666
- // the evil writer thread got in front of every single reader.
667
-
668
- // FIXME
669
- // Should we actually require that every reader observe the first change?
670
- // This is a matter of protocol rather than correctness...
671
-
672
- let mut reader_handles = Vec :: with_capacity ( R ) ;
673
-
674
- for _ in 0 ..R {
675
- let r = r. clone ( ) ;
676
- let observers = observers. clone ( ) ;
677
-
678
- // Spawn a thread that wants to observe the value that the main thread writes (not evil).
679
- let handle = thread:: spawn ( move || {
680
- // Will go to sleep since the main thread initially has the write lock.
681
- let read_guard = r. read ( ) . unwrap ( ) ;
682
- eprintln ! ( "\t Observed {}" , * read_guard) ;
683
-
684
- if * read_guard == 1 {
685
- observers. fetch_add ( 1 , Ordering :: Relaxed ) ;
686
- }
687
- } ) ;
688
-
689
- reader_handles. push ( handle) ;
690
- }
691
-
692
- // FIXME Come up with a better way to make sure everyone is sleeping.
693
- let eternity = time:: Duration :: from_secs ( 5 ) ;
694
-
695
- // Make sure that everyone else is actually sleeping.
696
- thread:: sleep ( eternity) ;
697
-
698
- // Spawn an evil thread that will try to write before the readers have read.
699
- let evil = r. clone ( ) ;
700
- let evil_handle = thread:: spawn ( move || {
701
- // Will go to sleep since the main thread initially has the write lock.
702
- let mut evil_guard = evil. write ( ) . unwrap ( ) ;
703
- eprintln ! ( "Evil thread is writing now" ) ;
704
- * evil_guard = 2 ;
705
- } ) ;
706
-
707
- // Make sure that everyone else is actually sleeping.
708
- thread:: sleep ( eternity) ;
709
-
710
- // Once everyone is asleep, set the value to 1.
711
- * main_write_guard = 1 ;
712
-
713
- // As of now, the `R` reader threads and the 1 evil thread _should_ be sleeping.
714
- eprintln ! ( "\n \n Beginning Test\n \n " ) ;
715
-
716
- // Atomically downgrade the write guard into a read guard.
717
- // This should wake up some of the reader threads, and allow them to also take the read lock.
718
- let main_read_guard = RwLockWriteGuard :: downgrade ( main_write_guard) ;
719
-
720
- // If the above is not atomic, then it is possible for the evil thread to get in front of the
721
- // readers and change the value to 2 instead.
722
- assert_eq ! ( * main_read_guard, 1 , "`downgrade` was not atomic" ) ;
723
-
724
- // By dropping all of the read guards, we allow the evil thread to make the change.
725
- drop ( main_read_guard) ;
726
-
727
- for handle in reader_handles {
728
- handle. join ( ) . unwrap ( ) ;
729
- }
730
-
731
- // Wait for the evil thread to set the value to 2.
732
- evil_handle. join ( ) . unwrap ( ) ;
733
-
734
- let final_check = r. read ( ) . unwrap ( ) ;
735
- assert_eq ! ( * final_check, 2 ) ;
736
-
737
- assert_ne ! ( observers. load( Ordering :: Relaxed ) , 0 , "No readers observed the correct value" ) ;
738
- }
0 commit comments