@@ -54,6 +54,22 @@ fn is_read_lockable(state: u32) -> bool {
5454 state & MASK < MAX_READERS && !has_readers_waiting ( state) && !has_writers_waiting ( state)
5555}
5656
57+ #[ inline]
58+ fn is_read_lockable_after_wakeup ( state : u32 ) -> bool {
59+ // We make a special case for checking if we can read-lock _after_ a reader thread that went to
60+ // sleep has been woken up by a call to `downgrade`.
61+ //
62+ // `downgrade` will wake up all readers and place the lock in read mode. Thus, there should be
63+ // no readers waiting and the lock should not be write-locked.
64+ //
65+ // If the lock happens to be unlocked, then we defer to the normal `is_read_lockable`
66+ // check that will prioritize any waiting writers first.
67+ state & MASK < MAX_READERS
68+ && !has_readers_waiting ( state)
69+ && !is_write_locked ( state)
70+ && !is_unlocked ( state)
71+ }
72+
5773#[ inline]
5874fn has_reached_max_readers ( state : u32 ) -> bool {
5975 state & MASK == MAX_READERS
@@ -101,11 +117,12 @@ impl RwLock {
101117
102118 #[ cold]
103119 fn read_contended ( & self ) {
120+ let mut has_slept = false ;
104121 let mut state = self . spin_read ( ) ;
105122
106123 loop {
107124 // If we can lock it, lock it.
108- if is_read_lockable ( state) {
125+ if has_slept && is_read_lockable_after_wakeup ( state ) || is_read_lockable ( state) {
109126 match self . state . compare_exchange_weak ( state, state + READ_LOCKED , Acquire , Relaxed )
110127 {
111128 Ok ( _) => return , // Locked!
@@ -116,6 +133,7 @@ impl RwLock {
116133 }
117134 }
118135
136+ // FIXME shouldn't this be an assert?
119137 // Check for overflow.
120138 if has_reached_max_readers ( state) {
121139 panic ! ( "too many active read locks on RwLock" ) ;
@@ -133,22 +151,11 @@ impl RwLock {
133151
134152 // Wait for the state to change.
135153 futex_wait ( & self . state , state | READERS_WAITING , None ) ;
154+ has_slept = true ;
136155
137- // FIXME make sure this works
138- // FIXME this can probably be more elegant
139- state = self . state . load ( Relaxed ) ;
140- if state & MASK < MAX_READERS && !has_readers_waiting ( state) {
141- match self . state . compare_exchange_weak ( state, state + READ_LOCKED , Acquire , Relaxed )
142- {
143- Ok ( _) => return , // Locked!
144- Err ( s) => {
145- state = s;
146- continue ;
147- }
148- }
149- }
150-
151- // Otherwise, spin again after waking up.
156+ // Spin again after waking up.
157+ // Note that if we were waken up by a call to `downgrade`, we will be read-locked, which
158+ // means that this will stop spinning immediately.
152159 state = self . spin_read ( ) ;
153160 }
154161 }
@@ -178,7 +185,6 @@ impl RwLock {
178185 }
179186 }
180187
181- // FIXME make sure this works
182188 #[ inline]
183189 pub unsafe fn downgrade ( & self ) {
184190 // Removes all the write bits and adds a single read bit.
0 commit comments