@@ -56,6 +56,22 @@ fn is_read_lockable(state: u32) -> bool {
56
56
state & MASK < MAX_READERS && !has_readers_waiting ( state) && !has_writers_waiting ( state)
57
57
}
58
58
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
+
59
75
#[ inline]
60
76
fn has_reached_max_readers ( state : u32 ) -> bool {
61
77
state & MASK == MAX_READERS
@@ -103,11 +119,12 @@ impl RwLock {
103
119
104
120
#[ cold]
105
121
fn read_contended ( & self ) {
122
+ let mut has_slept = false ;
106
123
let mut state = self . spin_read ( ) ;
107
124
108
125
loop {
109
126
// 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) {
111
128
match self . state . compare_exchange_weak ( state, state + READ_LOCKED , Acquire , Relaxed )
112
129
{
113
130
Ok ( _) => return , // Locked!
@@ -118,6 +135,7 @@ impl RwLock {
118
135
}
119
136
}
120
137
138
+ // FIXME shouldn't this be an assert?
121
139
// Check for overflow.
122
140
if has_reached_max_readers ( state) {
123
141
panic ! ( "too many active read locks on RwLock" ) ;
@@ -135,22 +153,11 @@ impl RwLock {
135
153
136
154
// Wait for the state to change.
137
155
futex_wait ( & self . state , state | READERS_WAITING , None ) ;
156
+ has_slept = true ;
138
157
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.
154
161
state = self . spin_read ( ) ;
155
162
}
156
163
}
@@ -180,7 +187,6 @@ impl RwLock {
180
187
}
181
188
}
182
189
183
- // FIXME make sure this works
184
190
#[ inline]
185
191
pub unsafe fn downgrade ( & self ) {
186
192
// Removes all the write bits and adds a single read bit.
0 commit comments