1
- use crate :: sync:: atomic:: AtomicU32 ;
2
1
use crate :: sync:: atomic:: Ordering :: { Acquire , Relaxed , Release } ;
3
- use crate :: sys:: futex:: { futex_wait, futex_wake, futex_wake_all} ;
2
+ use crate :: sys:: futex:: { Futex , Primitive , futex_wait, futex_wake, futex_wake_all} ;
4
3
5
4
pub struct RwLock {
6
5
// The state consists of a 30-bit reader counter, a 'readers waiting' flag, and a 'writers waiting' flag.
@@ -10,41 +9,41 @@ pub struct RwLock {
10
9
// 0x3FFF_FFFF: Write locked
11
10
// Bit 30: Readers are waiting on this futex.
12
11
// Bit 31: Writers are waiting on the writer_notify futex.
13
- state : AtomicU32 ,
12
+ state : Futex ,
14
13
// The 'condition variable' to notify writers through.
15
14
// Incremented on every signal.
16
- writer_notify : AtomicU32 ,
15
+ writer_notify : Futex ,
17
16
}
18
17
19
- const READ_LOCKED : u32 = 1 ;
20
- const MASK : u32 = ( 1 << 30 ) - 1 ;
21
- const WRITE_LOCKED : u32 = MASK ;
22
- const MAX_READERS : u32 = MASK - 1 ;
23
- const READERS_WAITING : u32 = 1 << 30 ;
24
- const WRITERS_WAITING : u32 = 1 << 31 ;
18
+ const READ_LOCKED : Primitive = 1 ;
19
+ const MASK : Primitive = ( 1 << 30 ) - 1 ;
20
+ const WRITE_LOCKED : Primitive = MASK ;
21
+ const MAX_READERS : Primitive = MASK - 1 ;
22
+ const READERS_WAITING : Primitive = 1 << 30 ;
23
+ const WRITERS_WAITING : Primitive = 1 << 31 ;
25
24
26
25
#[ inline]
27
- fn is_unlocked ( state : u32 ) -> bool {
26
+ fn is_unlocked ( state : Primitive ) -> bool {
28
27
state & MASK == 0
29
28
}
30
29
31
30
#[ inline]
32
- fn is_write_locked ( state : u32 ) -> bool {
31
+ fn is_write_locked ( state : Primitive ) -> bool {
33
32
state & MASK == WRITE_LOCKED
34
33
}
35
34
36
35
#[ inline]
37
- fn has_readers_waiting ( state : u32 ) -> bool {
36
+ fn has_readers_waiting ( state : Primitive ) -> bool {
38
37
state & READERS_WAITING != 0
39
38
}
40
39
41
40
#[ inline]
42
- fn has_writers_waiting ( state : u32 ) -> bool {
41
+ fn has_writers_waiting ( state : Primitive ) -> bool {
43
42
state & WRITERS_WAITING != 0
44
43
}
45
44
46
45
#[ inline]
47
- fn is_read_lockable ( state : u32 ) -> bool {
46
+ fn is_read_lockable ( state : Primitive ) -> bool {
48
47
// This also returns false if the counter could overflow if we tried to read lock it.
49
48
//
50
49
// We don't allow read-locking if there's readers waiting, even if the lock is unlocked
@@ -55,14 +54,14 @@ fn is_read_lockable(state: u32) -> bool {
55
54
}
56
55
57
56
#[ inline]
58
- fn has_reached_max_readers ( state : u32 ) -> bool {
57
+ fn has_reached_max_readers ( state : Primitive ) -> bool {
59
58
state & MASK == MAX_READERS
60
59
}
61
60
62
61
impl RwLock {
63
62
#[ inline]
64
63
pub const fn new ( ) -> Self {
65
- Self { state : AtomicU32 :: new ( 0 ) , writer_notify : AtomicU32 :: new ( 0 ) }
64
+ Self { state : Futex :: new ( 0 ) , writer_notify : Futex :: new ( 0 ) }
66
65
}
67
66
68
67
#[ inline]
@@ -225,7 +224,7 @@ impl RwLock {
225
224
/// If both are waiting, this will wake up only one writer, but will fall
226
225
/// back to waking up readers if there was no writer to wake up.
227
226
#[ cold]
228
- fn wake_writer_or_readers ( & self , mut state : u32 ) {
227
+ fn wake_writer_or_readers ( & self , mut state : Primitive ) {
229
228
assert ! ( is_unlocked( state) ) ;
230
229
231
230
// The readers waiting bit might be turned on at any point now,
@@ -290,7 +289,7 @@ impl RwLock {
290
289
291
290
/// Spin for a while, but stop directly at the given condition.
292
291
#[ inline]
293
- fn spin_until ( & self , f : impl Fn ( u32 ) -> bool ) -> u32 {
292
+ fn spin_until ( & self , f : impl Fn ( Primitive ) -> bool ) -> Primitive {
294
293
let mut spin = 100 ; // Chosen by fair dice roll.
295
294
loop {
296
295
let state = self . state . load ( Relaxed ) ;
@@ -303,13 +302,13 @@ impl RwLock {
303
302
}
304
303
305
304
#[ inline]
306
- fn spin_write ( & self ) -> u32 {
305
+ fn spin_write ( & self ) -> Primitive {
307
306
// Stop spinning when it's unlocked or when there's waiting writers, to keep things somewhat fair.
308
307
self . spin_until ( |state| is_unlocked ( state) || has_writers_waiting ( state) )
309
308
}
310
309
311
310
#[ inline]
312
- fn spin_read ( & self ) -> u32 {
311
+ fn spin_read ( & self ) -> Primitive {
313
312
// Stop spinning when it's unlocked or read locked, or when there's waiting threads.
314
313
self . spin_until ( |state| {
315
314
!is_write_locked ( state) || has_readers_waiting ( state) || has_writers_waiting ( state)
0 commit comments