Abstract the state type for futexes · qinheping/verify-rust-std@01bce29 (original) (raw)
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)
`