msr_core/sync/
atomic.rs

1#[cfg(loom)]
2#[allow(unused_imports)]
3pub(crate) use loom::sync::atomic::{AtomicBool, AtomicU64, AtomicU8, Ordering};
4
5#[cfg(not(loom))]
6#[allow(unused_imports)]
7pub(crate) use std::sync::atomic::{AtomicBool, AtomicU64, AtomicU8, Ordering};
8
9/// An atomic flag
10///
11/// Uses acquire/release memory ordering semantics for
12/// reliable handover.
13#[derive(Debug, Default)]
14pub struct OrderedAtomicFlag(AtomicBool);
15
16impl OrderedAtomicFlag {
17    pub fn reset(&self) {
18        self.0.store(false, Ordering::Release);
19    }
20
21    pub fn set(&self) {
22        self.0.store(true, Ordering::Release);
23    }
24
25    pub fn check_and_reset(&self) -> bool {
26        // If the CAS operation fails then the current value must have
27        // been `false`. The ordering on failure is irrelevant since
28        // the resulting value is discarded.
29        self.0
30            .compare_exchange(true, false, Ordering::AcqRel, Ordering::Relaxed)
31            .is_ok()
32    }
33
34    pub fn peek(&self) -> bool {
35        self.0.load(Ordering::Relaxed)
36    }
37
38    pub fn load(&self) -> bool {
39        self.0.load(Ordering::Acquire)
40    }
41}
42
43/// The observed effect of switching the progress hint
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub enum SwitchAtomicStateOk<T> {
46    Accepted {
47        previous_state: T,
48    },
49
50    /// Unchanged, i.e. already as desired
51    Ignored,
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub enum SwitchAtomicStateErr<T> {
56    Rejected { current_state: T },
57}
58
59pub type SwitchAtomicStateResult<T> = Result<SwitchAtomicStateOk<T>, SwitchAtomicStateErr<T>>;
60
61/// Atomic operations for state transitions
62///
63/// Needed for implementing state machines with atomic state transitions.
64pub trait AtomicState {
65    type State: Copy;
66
67    /// Peek the current state
68    ///
69    /// Uses relaxed memory ordering semantics.
70    fn peek(&self) -> Self::State;
71
72    /// Load the current state
73    ///
74    /// Uses the same memory ordering semantics as when switching
75    /// the state.
76    fn load(&self) -> Self::State;
77
78    /// Switch to the desired state unconditionally
79    ///
80    /// Replaces the current state with the desired state independent
81    /// of the current state and returns the previous state.
82    fn switch_to_desired(&self, desired_state: Self::State) -> SwitchAtomicStateOk<Self::State>;
83
84    /// Switch to the desired state conditionally
85    ///
86    /// Replaces the current state with the desired state if it equals
87    /// the given expected state and returns the previous state. Otherwise
88    /// returns the unmodified current state.
89    fn switch_from_expected_to_desired(
90        &self,
91        expected_state: Self::State,
92        desired_state: Self::State,
93    ) -> SwitchAtomicStateResult<Self::State>;
94}