@@ -5,8 +5,18 @@ 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:: sync:: RwLock as StdRwLock ;
8
9
use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
9
10
11
+ #[ allow( clippy:: identity_op) ]
12
+ const PHASE : usize = 1 << 0 ;
13
+ const ONE_WRITER : usize = 1 << 1 ;
14
+ const ONE_READER : usize = 1 << 2 ;
15
+ const WRITE_BITS : usize = ONE_WRITER | PHASE ;
16
+
17
+ // Sentinel for when no slot in the `Slab` has been dedicated to this object.
18
+ const WAIT_KEY_NONE : usize = usize:: max_value ( ) ;
19
+
10
20
struct State {
11
21
ins : AtomicUsize ,
12
22
out : AtomicUsize ,
@@ -33,16 +43,26 @@ impl AtomicState {
33
43
self . read . out . fetch_add ( ONE_READER , Ordering :: SeqCst )
34
44
}
35
45
46
+ #[ inline]
47
+ fn waiting_writers ( & self ) -> usize {
48
+ self . write . ins . load ( Ordering :: Relaxed )
49
+ }
50
+
36
51
#[ inline]
37
52
fn reserve_reader ( & self ) -> usize {
38
53
self . read . ins . fetch_add ( ONE_READER , Ordering :: SeqCst ) & WRITE_BITS
39
54
}
40
55
41
56
#[ inline]
42
- fn reserve_writer ( & self , phase : usize ) -> usize {
57
+ fn reserve_writer ( & self , ticket : usize ) -> usize {
43
58
self . read
44
59
. ins
45
- . fetch_add ( ONE_WRITER | phase, Ordering :: SeqCst )
60
+ . fetch_add ( ONE_WRITER | ( ticket & PHASE ) , Ordering :: SeqCst )
61
+ }
62
+
63
+ #[ inline]
64
+ fn reserve_transient_writer ( & self ) -> usize {
65
+ self . read . ins . fetch_add ( PHASE , Ordering :: SeqCst )
46
66
}
47
67
48
68
#[ inline]
@@ -71,6 +91,8 @@ pub struct RwLock<T: ?Sized> {
71
91
atomic : AtomicState ,
72
92
readers : WaiterSet ,
73
93
writers : WaiterSet ,
94
+ block_read_tickets : StdRwLock < ( ) > ,
95
+ block_write_tickets : StdRwLock < ( ) > ,
74
96
value : UnsafeCell < T > ,
75
97
}
76
98
@@ -80,15 +102,6 @@ impl<T: ?Sized> fmt::Debug for RwLock<T> {
80
102
}
81
103
}
82
104
83
- #[ allow( clippy:: identity_op) ]
84
- const PHASE : usize = 1 << 0 ;
85
- const ONE_WRITER : usize = 1 << 1 ;
86
- const ONE_READER : usize = 1 << 2 ;
87
- const WRITE_BITS : usize = ONE_WRITER | PHASE ;
88
-
89
- // Sentinel for when no slot in the `Slab` has been dedicated to this object.
90
- const WAIT_KEY_NONE : usize = usize:: max_value ( ) ;
91
-
92
105
impl < T > RwLock < T > {
93
106
/// Creates a new futures-aware read-write lock.
94
107
pub fn new ( t : T ) -> RwLock < T > {
@@ -105,6 +118,8 @@ impl<T> RwLock<T> {
105
118
} ,
106
119
readers : WaiterSet :: new ( ) ,
107
120
writers : WaiterSet :: new ( ) ,
121
+ block_read_tickets : StdRwLock :: new ( ( ) ) ,
122
+ block_write_tickets : StdRwLock :: new ( ( ) ) ,
108
123
value : UnsafeCell :: new ( t) ,
109
124
}
110
125
}
@@ -149,6 +164,54 @@ impl<T: ?Sized> RwLock<T> {
149
164
}
150
165
}
151
166
167
+ /// Attempt to acquire a read access lock synchronously.
168
+ pub fn try_read ( & self ) -> Option < RwLockReadGuard < ' _ , T > > {
169
+ let lock = self . block_read_tickets . write ( ) . unwrap ( ) ;
170
+ if self . atomic . phase ( ) == 0 {
171
+ self . atomic . reserve_reader ( ) ;
172
+ drop ( lock) ;
173
+ self . writers . notify_all ( ) ;
174
+ Some ( RwLockReadGuard { rwlock : self } )
175
+ } else {
176
+ drop ( lock) ;
177
+ self . writers . notify_all ( ) ;
178
+ None
179
+ }
180
+ }
181
+
182
+ /// Attempt to acquire a write access lock synchronously.
183
+ pub fn try_write ( & self ) -> Option < RwLockWriteGuard < ' _ , T > > {
184
+ let read_lock = self . block_read_tickets . write ( ) . unwrap ( ) ;
185
+ if self . atomic . phase ( ) == 0 {
186
+ let write_lock = self . block_write_tickets . write ( ) . unwrap ( ) ;
187
+ if self . atomic . waiting_writers ( ) == self . atomic . finished_writers ( )
188
+ && self . atomic . reserve_transient_writer ( ) == self . atomic . finished_readers ( )
189
+ {
190
+ self . atomic . insert_writer ( ) ;
191
+ drop ( write_lock) ;
192
+ drop ( read_lock) ;
193
+ self . writers . notify_all ( ) ;
194
+ Some ( RwLockWriteGuard { rwlock : self } )
195
+ } else if self . atomic . phase ( ) != 0 {
196
+ self . atomic . clear_phase ( ) ;
197
+ drop ( write_lock) ;
198
+ drop ( read_lock) ;
199
+ self . writers . notify_all ( ) ;
200
+ self . readers . notify_all ( ) ;
201
+ None
202
+ } else {
203
+ drop ( write_lock) ;
204
+ drop ( read_lock) ;
205
+ self . writers . notify_all ( ) ;
206
+ None
207
+ }
208
+ } else {
209
+ drop ( read_lock) ;
210
+ self . writers . notify_all ( ) ;
211
+ None
212
+ }
213
+ }
214
+
152
215
/// Returns a mutable reference to the underlying data.
153
216
///
154
217
/// Since this call borrows the lock mutably, no actual locking needs to
@@ -304,11 +367,13 @@ impl<'a, T: ?Sized> Future for RwLockWriteFuture<'a, T> {
304
367
305
368
match self . ticket {
306
369
None => {
370
+ let _write_lock = rwlock. block_write_tickets . read ( ) . unwrap ( ) ;
307
371
let ticket = rwlock. atomic . insert_writer ( ) ;
308
372
self . ticket = Some ( Ticket :: Write ( ticket) ) ;
309
373
if ticket == rwlock. atomic . finished_writers ( ) {
310
374
// Note that the WRITE_BITS are always cleared at this point.
311
- let ticket = rwlock. atomic . reserve_writer ( ticket & PHASE ) ;
375
+ let _read_lock = rwlock. block_read_tickets . read ( ) . unwrap ( ) ;
376
+ let ticket = rwlock. atomic . reserve_writer ( ticket) ;
312
377
self . ticket = Some ( Ticket :: Read ( ticket) ) ;
313
378
if ticket == rwlock. atomic . finished_readers ( ) {
314
379
self . rwlock = None ;
@@ -325,7 +390,8 @@ impl<'a, T: ?Sized> Future for RwLockWriteFuture<'a, T> {
325
390
Some ( Ticket :: Write ( ticket) ) => {
326
391
if ticket == rwlock. atomic . finished_writers ( ) {
327
392
// Note that the WRITE_BITS are always cleared at this point.
328
- let ticket = rwlock. atomic . reserve_writer ( ticket & PHASE ) ;
393
+ let _read_lock = rwlock. block_read_tickets . read ( ) . unwrap ( ) ;
394
+ let ticket = rwlock. atomic . reserve_writer ( ticket) ;
329
395
self . ticket = Some ( Ticket :: Read ( ticket) ) ;
330
396
if ticket == rwlock. atomic . finished_readers ( ) {
331
397
rwlock. writers . remove ( self . wait_key ) ;
0 commit comments