@@ -5,38 +5,49 @@ 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:: process;
9
8
use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
10
9
10
+ struct State {
11
+ ins : AtomicUsize ,
12
+ out : AtomicUsize ,
13
+ }
14
+
11
15
/// A futures-aware read-write lock.
12
16
pub struct RwLock < T : ?Sized > {
13
- state : AtomicUsize ,
17
+ read_state : State ,
18
+ write_state : State ,
14
19
readers : WaiterSet ,
15
20
writers : WaiterSet ,
16
21
value : UnsafeCell < T > ,
17
22
}
18
23
19
24
impl < T : ?Sized > fmt:: Debug for RwLock < T > {
20
25
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
21
- let state = self . state . load ( Ordering :: SeqCst ) ;
22
- f. debug_struct ( "RwLock" )
23
- . field ( "is_locked" , & ( ( state & IS_LOCKED ) != 0 ) )
24
- . field ( "readers" , & ( ( state & READ_COUNT ) >> 1 ) )
25
- . finish ( )
26
+ f. debug_struct ( "RwLock" ) . finish ( )
26
27
}
27
28
}
28
29
29
30
#[ allow( clippy:: identity_op) ]
30
- const IS_LOCKED : usize = 1 << 0 ;
31
- const ONE_READER : usize = 1 << 1 ;
32
- const READ_COUNT : usize = !( ONE_READER - 1 ) ;
33
- const MAX_READERS : usize = usize:: max_value ( ) >> 1 ;
31
+ const PHASE : usize = 1 << 0 ;
32
+ const ONE_WRITER : usize = 1 << 1 ;
33
+ const ONE_READER : usize = 1 << 2 ;
34
+ const WRITE_BITS : usize = ONE_WRITER | PHASE ;
35
+
36
+ // Sentinel for when no slot in the `Slab` has been dedicated to this object.
37
+ const WAIT_KEY_NONE : usize = usize:: max_value ( ) ;
34
38
35
39
impl < T > RwLock < T > {
36
40
/// Creates a new futures-aware read-write lock.
37
41
pub fn new ( t : T ) -> RwLock < T > {
38
42
RwLock {
39
- state : AtomicUsize :: new ( 0 ) ,
43
+ read_state : State {
44
+ ins : AtomicUsize :: new ( 0 ) ,
45
+ out : AtomicUsize :: new ( 0 ) ,
46
+ } ,
47
+ write_state : State {
48
+ ins : AtomicUsize :: new ( 0 ) ,
49
+ out : AtomicUsize :: new ( 0 ) ,
50
+ } ,
40
51
readers : WaiterSet :: new ( ) ,
41
52
writers : WaiterSet :: new ( ) ,
42
53
value : UnsafeCell :: new ( t) ,
@@ -59,52 +70,14 @@ impl<T> RwLock<T> {
59
70
}
60
71
61
72
impl < T : ?Sized > RwLock < T > {
62
- /// Attempt to acquire a lock with shared read access immediately.
63
- ///
64
- /// If the lock is currently held by a writer, this will return `None`.
65
- pub fn try_read ( & self ) -> Option < RwLockReadGuard < ' _ , T > > {
66
- let mut state = self . state . load ( Ordering :: Acquire ) ;
67
-
68
- loop {
69
- if state & IS_LOCKED != 0 {
70
- return None ;
71
- }
72
-
73
- if state > MAX_READERS {
74
- process:: abort ( ) ;
75
- }
76
-
77
- match self . state . compare_exchange_weak (
78
- state,
79
- state + ONE_READER ,
80
- Ordering :: SeqCst ,
81
- Ordering :: SeqCst ,
82
- ) {
83
- Ok ( _) => return Some ( RwLockReadGuard { rwlock : self } ) ,
84
- Err ( s) => state = s,
85
- }
86
- }
87
- }
88
-
89
- /// Attempt to acquire a lock with exclusive write access immediately.
90
- ///
91
- /// If there are any other locks, either for read or write access, this
92
- /// will return `None`.
93
- pub fn try_write ( & self ) -> Option < RwLockWriteGuard < ' _ , T > > {
94
- if self . state . compare_and_swap ( 0 , IS_LOCKED , Ordering :: SeqCst ) == 0 {
95
- Some ( RwLockWriteGuard { rwlock : self } )
96
- } else {
97
- None
98
- }
99
- }
100
-
101
73
/// Acquire a read access lock asynchronously.
102
74
///
103
75
/// This method returns a future that will resolve once all write access
104
76
/// locks have been dropped.
105
77
pub fn read ( & self ) -> RwLockReadFuture < ' _ , T > {
106
78
RwLockReadFuture {
107
79
rwlock : Some ( self ) ,
80
+ ticket : None ,
108
81
wait_key : WAIT_KEY_NONE ,
109
82
}
110
83
}
@@ -116,6 +89,7 @@ impl<T: ?Sized> RwLock<T> {
116
89
pub fn write ( & self ) -> RwLockWriteFuture < ' _ , T > {
117
90
RwLockWriteFuture {
118
91
rwlock : Some ( self ) ,
92
+ tickets : ( None , None ) ,
119
93
wait_key : WAIT_KEY_NONE ,
120
94
}
121
95
}
@@ -133,22 +107,20 @@ impl<T: ?Sized> RwLock<T> {
133
107
///
134
108
/// let mut rwlock = RwLock::new(0);
135
109
/// *rwlock.get_mut() = 10;
136
- /// assert_eq!(*rwlock.lock ().await, 10);
110
+ /// assert_eq!(*rwlock.read ().await, 10);
137
111
/// # });
138
112
/// ```
139
113
pub fn get_mut ( & mut self ) -> & mut T {
140
114
unsafe { & mut * self . value . get ( ) }
141
115
}
142
116
}
143
117
144
- // Sentinel for when no slot in the `Slab` has been dedicated to this object.
145
- const WAIT_KEY_NONE : usize = usize:: max_value ( ) ;
146
-
147
118
/// A future which resolves when the target read access lock has been successfully
148
119
/// acquired.
149
120
pub struct RwLockReadFuture < ' a , T : ?Sized > {
150
121
// `None` indicates that the mutex was successfully acquired.
151
122
rwlock : Option < & ' a RwLock < T > > ,
123
+ ticket : Option < usize > ,
152
124
wait_key : usize ,
153
125
}
154
126
@@ -157,6 +129,7 @@ impl<T: ?Sized> fmt::Debug for RwLockReadFuture<'_, T> {
157
129
f. debug_struct ( "RwLockReadFuture" )
158
130
. field ( "was_acquired" , & self . rwlock . is_none ( ) )
159
131
. field ( "rwlock" , & self . rwlock )
132
+ . field ( "ticket" , & self . ticket )
160
133
. field (
161
134
"wait_key" ,
162
135
& ( if self . wait_key == WAIT_KEY_NONE {
@@ -183,37 +156,43 @@ impl<'a, T: ?Sized> Future for RwLockReadFuture<'a, T> {
183
156
. rwlock
184
157
. expect ( "polled RwLockReadFuture after completion" ) ;
185
158
186
- if let Some ( lock) = rwlock. try_read ( ) {
159
+ // The ticket is defined by the write bits stored within the read-in count
160
+ let ticket = * self . ticket . get_or_insert_with ( || {
161
+ rwlock
162
+ . read_state
163
+ . ins
164
+ . fetch_add ( ONE_READER , Ordering :: SeqCst )
165
+ & WRITE_BITS
166
+ } ) ;
167
+
168
+ // Safe to create guard when either there are no writers (ticket == 0) or if
169
+ // at least one of the two write bits change.
170
+ // Writers always wait until the current reader phase completes before acquiring
171
+ // the lock; thus the PHASE bit both maintains the read-write condition and
172
+ // prevents deadlock in the case that this line isn't reached before a writer sets
173
+ // the ONE_WRITER bit.
174
+ if ticket == 0 || ticket != rwlock. read_state . ins . load ( Ordering :: Relaxed ) & WRITE_BITS {
187
175
if self . wait_key != WAIT_KEY_NONE {
188
176
rwlock. readers . remove ( self . wait_key ) ;
189
177
}
190
178
self . rwlock = None ;
191
- return Poll :: Ready ( lock) ;
192
- }
193
-
194
- if self . wait_key == WAIT_KEY_NONE {
195
- self . wait_key = rwlock. readers . insert ( cx. waker ( ) ) ;
179
+ Poll :: Ready ( RwLockReadGuard { rwlock } )
196
180
} else {
197
- rwlock. readers . register ( self . wait_key , cx. waker ( ) ) ;
198
- }
199
-
200
- // Ensure that we haven't raced `RwLockWriteGuard::drop`'s unlock path by
201
- // attempting to acquire the lock again.
202
- if let Some ( lock) = rwlock. try_read ( ) {
203
- rwlock. readers . remove ( self . wait_key ) ;
204
- self . rwlock = None ;
205
- return Poll :: Ready ( lock) ;
181
+ if self . wait_key == WAIT_KEY_NONE {
182
+ self . wait_key = rwlock. readers . insert ( cx. waker ( ) ) ;
183
+ } else {
184
+ rwlock. readers . register ( self . wait_key , cx. waker ( ) ) ;
185
+ }
186
+ Poll :: Pending
206
187
}
207
-
208
- Poll :: Pending
209
188
}
210
189
}
211
190
212
191
impl < T : ?Sized > Drop for RwLockReadFuture < ' _ , T > {
213
192
fn drop ( & mut self ) {
214
- if let Some ( rwlock ) = self . rwlock {
193
+ if let Some ( _ ) = self . rwlock {
215
194
if self . wait_key != WAIT_KEY_NONE {
216
- rwlock . readers . remove ( self . wait_key ) ;
195
+ panic ! ( "RwLockReadFuture dropped before completion" ) ;
217
196
}
218
197
}
219
198
}
@@ -223,6 +202,9 @@ impl<T: ?Sized> Drop for RwLockReadFuture<'_, T> {
223
202
/// acquired.
224
203
pub struct RwLockWriteFuture < ' a , T : ?Sized > {
225
204
rwlock : Option < & ' a RwLock < T > > ,
205
+ // The left ticket is used when waiting for other writers to finish, the right
206
+ // ticket is used when waiting on the current reader phase to finish.
207
+ tickets : ( Option < usize > , Option < usize > ) ,
226
208
wait_key : usize ,
227
209
}
228
210
@@ -257,42 +239,72 @@ impl<'a, T: ?Sized> Future for RwLockWriteFuture<'a, T> {
257
239
. rwlock
258
240
. expect ( "polled RwLockWriteFuture after completion" ) ;
259
241
260
- if let Some ( lock) = rwlock. try_write ( ) {
261
- if self . wait_key != WAIT_KEY_NONE {
262
- rwlock. writers . remove ( self . wait_key ) ;
242
+ match self . tickets {
243
+ ( None , None ) => {
244
+ let ticket = rwlock
245
+ . write_state
246
+ . ins
247
+ . fetch_add ( 1 , Ordering :: SeqCst ) ;
248
+ self . tickets . 0 = Some ( ticket) ;
249
+ if ticket == rwlock. write_state . out . load ( Ordering :: Relaxed ) {
250
+ // Note that the WRITE_BITS are always cleared at this point.
251
+ let ticket = rwlock
252
+ . read_state
253
+ . ins
254
+ . fetch_add ( ONE_WRITER | ( ticket & PHASE ) , Ordering :: SeqCst ) ;
255
+ self . tickets . 1 = Some ( ticket) ;
256
+ if ticket == rwlock. read_state . out . load ( Ordering :: Relaxed ) {
257
+ self . rwlock = None ;
258
+ Poll :: Ready ( RwLockWriteGuard { rwlock } )
259
+ } else {
260
+ self . wait_key = rwlock. writers . insert ( cx. waker ( ) ) ;
261
+ Poll :: Pending
262
+ }
263
+ } else {
264
+ self . wait_key = rwlock. writers . insert ( cx. waker ( ) ) ;
265
+ Poll :: Pending
266
+ }
267
+ }
268
+ ( Some ( ticket) , None ) => {
269
+ if ticket == rwlock. write_state . out . load ( Ordering :: Relaxed ) {
270
+ // Note that the WRITE_BITS are always cleared at this point.
271
+ let ticket = rwlock
272
+ . read_state
273
+ . ins
274
+ . fetch_add ( ONE_WRITER | ( ticket & PHASE ) , Ordering :: SeqCst ) ;
275
+ self . tickets . 1 = Some ( ticket) ;
276
+ if ticket == rwlock. read_state . out . load ( Ordering :: Relaxed ) {
277
+ rwlock. writers . remove ( self . wait_key ) ;
278
+ self . rwlock = None ;
279
+ Poll :: Ready ( RwLockWriteGuard { rwlock } )
280
+ } else {
281
+ rwlock. writers . register ( self . wait_key , cx. waker ( ) ) ;
282
+ Poll :: Pending
283
+ }
284
+ } else {
285
+ rwlock. writers . register ( self . wait_key , cx. waker ( ) ) ;
286
+ Poll :: Pending
287
+ }
288
+ }
289
+ ( _, Some ( ticket) ) => {
290
+ if ticket == rwlock. read_state . out . load ( Ordering :: Relaxed ) {
291
+ rwlock. writers . remove ( self . wait_key ) ;
292
+ self . rwlock = None ;
293
+ Poll :: Ready ( RwLockWriteGuard { rwlock } )
294
+ } else {
295
+ rwlock. writers . register ( self . wait_key , cx. waker ( ) ) ;
296
+ Poll :: Pending
297
+ }
263
298
}
264
- self . rwlock = None ;
265
- return Poll :: Ready ( lock) ;
266
- }
267
-
268
- if self . wait_key == WAIT_KEY_NONE {
269
- self . wait_key = rwlock. writers . insert ( cx. waker ( ) ) ;
270
- } else {
271
- rwlock. writers . register ( self . wait_key , cx. waker ( ) ) ;
272
- }
273
-
274
- // Ensure that we haven't raced `RwLockWriteGuard::drop` or
275
- // `RwLockReadGuard::drop`'s unlock path by attempting to acquire
276
- // the lock again.
277
- if let Some ( lock) = rwlock. try_write ( ) {
278
- rwlock. writers . remove ( self . wait_key ) ;
279
- self . rwlock = None ;
280
- return Poll :: Ready ( lock) ;
281
299
}
282
-
283
- Poll :: Pending
284
300
}
285
301
}
286
302
287
303
impl < T : ?Sized > Drop for RwLockWriteFuture < ' _ , T > {
288
304
fn drop ( & mut self ) {
289
- if let Some ( rwlock ) = self . rwlock {
305
+ if let Some ( _ ) = self . rwlock {
290
306
if self . wait_key != WAIT_KEY_NONE {
291
- // This future was dropped before it acquired the rwlock.
292
- //
293
- // Remove ourselves from the map, waking up another waiter if we
294
- // had been awoken to acquire the lock.
295
- rwlock. writers . cancel ( self . wait_key ) ;
307
+ panic ! ( "RwLockWriteFuture dropped before completion" ) ;
296
308
}
297
309
}
298
310
}
@@ -316,15 +328,17 @@ impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLockReadGuard<'_, T> {
316
328
317
329
impl < T : ?Sized > Drop for RwLockReadGuard < ' _ , T > {
318
330
fn drop ( & mut self ) {
319
- let old_state = self . rwlock . state . fetch_sub ( ONE_READER , Ordering :: SeqCst ) ;
320
- if old_state & READ_COUNT == ONE_READER {
321
- self . rwlock . writers . notify_any ( ) ;
322
- }
331
+ self . rwlock
332
+ . read_state
333
+ . out
334
+ . fetch_add ( ONE_READER , Ordering :: SeqCst ) ;
335
+ self . rwlock . writers . notify_all ( ) ;
323
336
}
324
337
}
325
338
326
339
impl < T : ?Sized > Deref for RwLockReadGuard < ' _ , T > {
327
340
type Target = T ;
341
+
328
342
fn deref ( & self ) -> & T {
329
343
unsafe { & * self . rwlock . value . get ( ) }
330
344
}
@@ -354,10 +368,10 @@ impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLockWriteGuard<'_, T> {
354
368
355
369
impl < T : ?Sized > Drop for RwLockWriteGuard < ' _ , T > {
356
370
fn drop ( & mut self ) {
357
- self . rwlock . state . store ( 0 , Ordering :: SeqCst ) ;
358
- if ! self . rwlock . readers . notify_all ( ) {
359
- self . rwlock . writers . notify_any ( ) ;
360
- }
371
+ self . rwlock . read_state . ins . fetch_and ( ! WRITE_BITS , Ordering :: Relaxed ) ;
372
+ self . rwlock . write_state . out . fetch_add ( 1 , Ordering :: Relaxed ) ;
373
+ self . rwlock . writers . notify_all ( ) ;
374
+ self . rwlock . readers . notify_all ( ) ;
361
375
}
362
376
}
363
377
@@ -388,13 +402,3 @@ unsafe impl<T: ?Sized + Sync> Sync for RwLockReadGuard<'_, T> {}
388
402
389
403
unsafe impl < T : ?Sized + Send > Send for RwLockWriteGuard < ' _ , T > { }
390
404
unsafe impl < T : ?Sized + Sync > Sync for RwLockWriteGuard < ' _ , T > { }
391
-
392
- #[ test]
393
- fn test_rwlock_guard_debug_not_recurse ( ) {
394
- let rwlock = RwLock :: new ( 42 ) ;
395
- let guard = rwlock. try_read ( ) . unwrap ( ) ;
396
- let _ = format ! ( "{:?}" , guard) ;
397
- drop ( guard) ;
398
- let guard = rwlock. try_write ( ) . unwrap ( ) ;
399
- let _ = format ! ( "{:?}" , guard) ;
400
- }
0 commit comments