@@ -5,8 +5,8 @@ use std::cell::UnsafeCell;
5
5
use std:: fmt;
6
6
use std:: ops:: { Deref , DerefMut } ;
7
7
use std:: pin:: Pin ;
8
- use std:: sync:: RwLock as StdRwLock ;
9
8
use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
9
+ use std:: sync:: RwLock as StdRwLock ;
10
10
11
11
#[ allow( clippy:: identity_op) ]
12
12
const PHASE : usize = 1 << 0 ;
@@ -43,6 +43,12 @@ impl AtomicState {
43
43
self . read . out . fetch_add ( ONE_READER , Ordering :: SeqCst )
44
44
}
45
45
46
+ #[ cfg( test) ]
47
+ #[ inline]
48
+ fn waiting_readers ( & self ) -> usize {
49
+ self . read . ins . load ( Ordering :: Relaxed )
50
+ }
51
+
46
52
#[ inline]
47
53
fn waiting_writers ( & self ) -> usize {
48
54
self . write . ins . load ( Ordering :: Relaxed )
@@ -98,7 +104,25 @@ pub struct RwLock<T: ?Sized> {
98
104
99
105
impl < T : ?Sized > fmt:: Debug for RwLock < T > {
100
106
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 ( )
102
126
}
103
127
}
104
128
@@ -125,15 +149,6 @@ impl<T> RwLock<T> {
125
149
}
126
150
127
151
/// 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
- /// ```
137
152
pub fn into_inner ( self ) -> T {
138
153
self . value . into_inner ( )
139
154
}
@@ -216,18 +231,6 @@ impl<T: ?Sized> RwLock<T> {
216
231
///
217
232
/// Since this call borrows the lock mutably, no actual locking needs to
218
233
/// 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
- /// ```
231
234
pub fn get_mut ( & mut self ) -> & mut T {
232
235
unsafe { & mut * self . value . get ( ) }
233
236
}
@@ -518,3 +521,113 @@ unsafe impl<T: ?Sized + Sync> Sync for RwLockReadGuard<'_, T> {}
518
521
519
522
unsafe impl < T : ?Sized + Send > Send for RwLockWriteGuard < ' _ , T > { }
520
523
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