@@ -56,6 +56,22 @@ fn is_read_lockable(state: u32) -> bool {
5656 state & MASK < MAX_READERS && !has_readers_waiting ( state) && !has_writers_waiting ( state)
5757}
5858
59+ #[ inline]
60+ fn is_read_lockable_after_wakeup ( state : u32 ) -> bool {
61+ // We make a special case for checking if we can read-lock _after_ a reader thread that went to
62+ // sleep has been woken up by a call to `downgrade`.
63+ //
64+ // `downgrade` will wake up all readers and place the lock in read mode. Thus, there should be
65+ // no readers waiting and the lock should not be write-locked.
66+ //
67+ // If the lock happens to be unlocked, then we defer to the normal `is_read_lockable`
68+ // check that will prioritize any waiting writers first.
69+ state & MASK < MAX_READERS
70+ && !has_readers_waiting ( state)
71+ && !is_write_locked ( state)
72+ && !is_unlocked ( state)
73+ }
74+
5975#[ inline]
6076fn has_reached_max_readers ( state : u32 ) -> bool {
6177 state & MASK == MAX_READERS
@@ -103,11 +119,12 @@ impl RwLock {
103119
104120 #[ cold]
105121 fn read_contended ( & self ) {
122+ let mut has_slept = false ;
106123 let mut state = self . spin_read ( ) ;
107124
108125 loop {
109126 // If we can lock it, lock it.
110- if is_read_lockable ( state) {
127+ if has_slept && is_read_lockable_after_wakeup ( state ) || is_read_lockable ( state) {
111128 match self . state . compare_exchange_weak ( state, state + READ_LOCKED , Acquire , Relaxed )
112129 {
113130 Ok ( _) => return , // Locked!
@@ -118,6 +135,7 @@ impl RwLock {
118135 }
119136 }
120137
138+ // FIXME shouldn't this be an assert?
121139 // Check for overflow.
122140 if has_reached_max_readers ( state) {
123141 panic ! ( "too many active read locks on RwLock" ) ;
@@ -135,22 +153,11 @@ impl RwLock {
135153
136154 // Wait for the state to change.
137155 futex_wait ( & self . state , state | READERS_WAITING , None ) ;
156+ has_slept = true ;
138157
139- // FIXME make sure this works
140- // FIXME this can probably be more elegant
141- state = self . state . load ( Relaxed ) ;
142- if state & MASK < MAX_READERS && !has_readers_waiting ( state) {
143- match self . state . compare_exchange_weak ( state, state + READ_LOCKED , Acquire , Relaxed )
144- {
145- Ok ( _) => return , // Locked!
146- Err ( s) => {
147- state = s;
148- continue ;
149- }
150- }
151- }
152-
153- // Otherwise, spin again after waking up.
158+ // Spin again after waking up.
159+ // Note that if we were waken up by a call to `downgrade`, we will be read-locked, which
160+ // means that this will stop spinning immediately.
154161 state = self . spin_read ( ) ;
155162 }
156163 }
@@ -180,7 +187,6 @@ impl RwLock {
180187 }
181188 }
182189
183- // FIXME make sure this works
184190 #[ inline]
185191 pub unsafe fn downgrade ( & self ) {
186192 // Removes all the write bits and adds a single read bit.
0 commit comments