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