]> git.proxmox.com Git - cargo.git/blob - vendor/crossbeam-utils/src/atomic/seq_lock.rs
New upstream version 0.47.0
[cargo.git] / vendor / crossbeam-utils / src / atomic / seq_lock.rs
1 use core::sync::atomic::{self, AtomicUsize, Ordering};
2
3 use Backoff;
4
5 /// A simple stamped lock.
6 pub struct SeqLock {
7 /// The current state of the lock.
8 ///
9 /// All bits except the least significant one hold the current stamp. When locked, the state
10 /// equals 1 and doesn't contain a valid stamp.
11 state: AtomicUsize,
12 }
13
14 impl SeqLock {
15 pub const INIT: Self = Self {
16 state: AtomicUsize::new(0),
17 };
18
19 /// If not locked, returns the current stamp.
20 ///
21 /// This method should be called before optimistic reads.
22 #[inline]
23 pub fn optimistic_read(&self) -> Option<usize> {
24 let state = self.state.load(Ordering::Acquire);
25 if state == 1 {
26 None
27 } else {
28 Some(state)
29 }
30 }
31
32 /// Returns `true` if the current stamp is equal to `stamp`.
33 ///
34 /// This method should be called after optimistic reads to check whether they are valid. The
35 /// argument `stamp` should correspond to the one returned by method `optimistic_read`.
36 #[inline]
37 pub fn validate_read(&self, stamp: usize) -> bool {
38 atomic::fence(Ordering::Acquire);
39 self.state.load(Ordering::Relaxed) == stamp
40 }
41
42 /// Grabs the lock for writing.
43 #[inline]
44 pub fn write(&'static self) -> SeqLockWriteGuard {
45 let backoff = Backoff::new();
46 loop {
47 let previous = self.state.swap(1, Ordering::Acquire);
48
49 if previous != 1 {
50 atomic::fence(Ordering::Release);
51
52 return SeqLockWriteGuard {
53 lock: self,
54 state: previous,
55 };
56 }
57
58 backoff.snooze();
59 }
60 }
61 }
62
63 /// An RAII guard that releases the lock and increments the stamp when dropped.
64 pub struct SeqLockWriteGuard {
65 /// The parent lock.
66 lock: &'static SeqLock,
67
68 /// The stamp before locking.
69 state: usize,
70 }
71
72 impl SeqLockWriteGuard {
73 /// Releases the lock without incrementing the stamp.
74 #[inline]
75 pub fn abort(self) {
76 self.lock.state.store(self.state, Ordering::Release);
77 }
78 }
79
80 impl Drop for SeqLockWriteGuard {
81 #[inline]
82 fn drop(&mut self) {
83 // Release the lock and increment the stamp.
84 self.lock
85 .state
86 .store(self.state.wrapping_add(2), Ordering::Release);
87 }
88 }