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)

`