Skip to main content

debra_common/
thread.rs

1//! Concurrently accessible state of threads participating in the reclamation.
2
3use core::fmt;
4use core::sync::atomic::{AtomicUsize, Ordering};
5
6use crate::epoch::Epoch;
7
8use self::State::{Active, Inactive};
9
10const INACTIVE_BIT: usize = 0b1;
11
12////////////////////////////////////////////////////////////////////////////////////////////////////
13// ThreadState
14////////////////////////////////////////////////////////////////////////////////////////////////////
15
16/// The concurrently accessible state of a thread, containing information about
17/// the thread's current [`Epoch`] and it's [`State`].
18#[derive(Debug)]
19pub struct ThreadState(AtomicUsize);
20
21impl ThreadState {
22    /// Creates a new [`ThreadState`] for the current `global_epoch` and in
23    /// [`Inactive`][State::Inactive] state.
24    #[inline]
25    pub fn new(global_epoch: Epoch) -> Self {
26        Self(AtomicUsize::new(global_epoch.into_inner() | INACTIVE_BIT))
27    }
28
29    /// Returns `true` if `other` is an aliased reference to `self`.
30    #[inline]
31    pub fn is_same(&self, other: &Self) -> bool {
32        self as *const Self == other as *const Self
33    }
34
35    /// Loads the thread's current [`Epoch`] and its ['State']
36    ///
37    /// `load` takes an [`Ordering`][ordering] argument, which describes the
38    /// memory ordering of this operation.
39    ///
40    /// # Panics
41    ///
42    /// Panics if `order` is [`Release`][release] or [`AcqRel`][acq_rel].
43    ///
44    /// [ordering]: core::sync::atomic::Ordering
45    /// [release]: core::sync::atomic::Ordering::Release
46    /// [acq_rel]: core::sync::atomic::Ordering::AcqRel
47    #[inline]
48    pub fn load(&self, order: Ordering) -> (Epoch, State) {
49        let state = self.0.load(order);
50        (Epoch::with_epoch(state & !INACTIVE_BIT), State::from(state & INACTIVE_BIT == 0))
51    }
52
53    /// Stores an `epoch` and a `state` into the current thread state.
54    ///
55    /// `store` takes an [`Ordering`][ordering] argument, which describes the
56    /// memory ordering of this operation.
57    ///
58    /// # Panics
59    ///
60    /// Panics if `order` is [`Release`][release] or [`AcqRel`][acq_rel].
61    ///
62    /// [ordering]: core::sync::atomic::Ordering
63    /// [release]: core::sync::atomic::Ordering::Release
64    /// [acq_rel]: core::sync::atomic::Ordering::AcqRel
65    #[inline]
66    pub fn store(&self, epoch: Epoch, state: State, order: Ordering) {
67        match state {
68            Active => self.0.store(epoch.into_inner(), order),
69            Inactive => self.0.store(epoch.into_inner() | INACTIVE_BIT, order),
70        };
71    }
72}
73
74impl fmt::Display for ThreadState {
75    #[inline]
76    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
77        let (epoch, state) = self.load(Ordering::SeqCst);
78        write!(f, "epoch {}, state: {}", epoch, state)
79    }
80}
81
82////////////////////////////////////////////////////////////////////////////////////////////////////
83// State
84////////////////////////////////////////////////////////////////////////////////////////////////////
85
86/// The state of a thread with regards to reading memory.
87#[derive(Debug, Copy, Clone, Eq, Ord, PartialEq, PartialOrd)]
88pub enum State {
89    /// The thread is active, i.e. could be currently reading values from shared
90    /// memory and other threads must not reclaim memory.
91    Active,
92    /// The thread is currently inactive, i.e. is not currently reading values
93    /// from shared memory.
94    Inactive,
95}
96
97impl From<bool> for State {
98    #[inline]
99    fn from(is_active: bool) -> Self {
100        if is_active {
101            Active
102        } else {
103            Inactive
104        }
105    }
106}
107
108impl fmt::Display for State {
109    #[inline]
110    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
111        match *self {
112            Active => write!(f, "active"),
113            Inactive => write!(f, "inactive"),
114        }
115    }
116}
117
118#[cfg(test)]
119mod tests {
120    use std::sync::atomic::Ordering::Relaxed;
121
122    use crate::epoch::Epoch;
123
124    use super::{
125        State::{self, Active, Inactive},
126        ThreadState,
127    };
128
129    #[test]
130    fn thread_state_equality() {
131        let epoch = Epoch::with_epoch(128);
132        let thread_state = ThreadState::new(epoch);
133        let other_thread_state = ThreadState::new(epoch);
134
135        assert!(thread_state.is_same(&thread_state));
136        assert!(!thread_state.is_same(&other_thread_state));
137    }
138
139    #[test]
140    fn load_thread_state() {
141        let init_epoch = Epoch::with_epoch(128);
142        let thread_state = ThreadState::new(init_epoch);
143        let (epoch, state) = thread_state.load(Relaxed);
144
145        assert_eq!(init_epoch, epoch);
146        assert_eq!(state, Inactive);
147    }
148
149    #[test]
150    fn store_thread_state() {
151        let init_epoch = Epoch::with_epoch(1000);
152        let thread_state = ThreadState::new(init_epoch);
153        let next_epoch = init_epoch + 1;
154
155        thread_state.store(next_epoch, Active, Relaxed);
156        let (epoch, state) = thread_state.load(Relaxed);
157
158        assert_eq!(epoch, next_epoch);
159        assert_eq!(state, Active);
160    }
161
162    #[test]
163    fn from_bool() {
164        assert_eq!(Active, State::from(true));
165        assert_eq!(Inactive, State::from(false));
166    }
167}