kernel_api/threading/state.rs
1use core::fmt::{Debug, Formatter};
2use core::sync::atomic::{AtomicU64, Ordering};
3
4const fn into_raw(state: ThreadState) -> u64 {
5 // SAFETY: pointer is derived from a reference to a `repr(u8)` enum
6 let tag = u64::from(unsafe { *(&raw const state).cast::<u8>() });
7
8 match state {
9 ThreadState::Killed(exit_code) | ThreadState::Zombie(exit_code) => {
10 let upper = exit_code.cast_unsigned();
11 (u64::from(upper) << 32) | tag
12 }
13 _ => tag,
14 }
15}
16
17fn from_raw(raw: u64) -> ThreadState {
18 let tag = raw.truncate::<u8>();
19
20 match tag {
21 0 => ThreadState::Ready,
22 1 => ThreadState::Running,
23 2 => ThreadState::Parked,
24 3 => ThreadState::NearlyParked,
25 4 => ThreadState::Killed((raw >> 32).truncate::<u32>().cast_signed()),
26 5 => ThreadState::Zombie((raw >> 32).truncate::<u32>().cast_signed()),
27 _ => unreachable!("invalid thread state"),
28 }
29}
30
31/// An atomic version of [`ThreadState`].
32pub struct AtomicThreadState(AtomicU64);
33
34impl AtomicThreadState {
35 /// Creates a new `AtomicThreadState` from the given [`ThreadState`].
36 ///
37 /// # Examples
38 ///
39 /// ```
40 /// use kernel_api::threading::{ThreadState, AtomicThreadState};
41 ///
42 /// let state = AtomicThreadState::new(ThreadState::Running);
43 /// assert!(state.running());
44 /// ```
45 #[must_use]
46 pub const fn new(state: ThreadState) -> Self {
47 Self(AtomicU64::new(into_raw(state)))
48 }
49
50 /// Atomically updates `self` to `state`.
51 ///
52 /// `store` takes an [`Ordering`] argument which describes the memory ordering of this operation.
53 /// Possible values are [`SeqCst`](`Ordering::SeqCst`), [`Release`](`Ordering::Release`) and [`Relaxed`](`Ordering::Relaxed`).
54 ///
55 /// # Panics
56 ///
57 /// Panics if `ordering` is [`Acquire`](`Ordering::Acquire`) or [`AcqRel`](`Ordering::AcqRel`).
58 ///
59 /// # Examples
60 ///
61 /// ```
62 /// use kernel_api::threading::{ThreadState, AtomicThreadState};
63 /// use core::sync::atomic::Ordering;
64 ///
65 /// let state = AtomicThreadState::new(ThreadState::Running);
66 /// assert!(state.running());
67 /// state.store(ThreadState::Killed(-1), Ordering::SeqCst);
68 /// assert!(!state.running());
69 /// ```
70 pub fn store(&self, state: ThreadState, ordering: Ordering) {
71 self.0.store(into_raw(state), ordering);
72 }
73
74 /// Atomically retrieves the current state of `self`.
75 ///
76 /// `load` takes an [`Ordering`] argument which describes the memory ordering of this operation.
77 /// Possible values are [`SeqCst`](`Ordering::SeqCst`), [`Acquire`](`Ordering::Acquire`) and [`Relaxed`](`Ordering::Relaxed`).
78 ///
79 /// # Panics
80 ///
81 /// Panics if `ordering` is [`Release`](`Ordering::Release`) or [`AcqRel`](`Ordering::AcqRel`).
82 ///
83 /// # Examples
84 ///
85 /// ```
86 /// use kernel_api::threading::{ThreadState, AtomicThreadState};
87 /// use core::sync::atomic::Ordering;
88 /// use core::assert_matches;
89 ///
90 /// let state = AtomicThreadState::new(ThreadState::Running);
91 /// let state = state.load(Ordering::SeqCst);
92 /// assert_matches!(state, ThreadState::Running);
93 /// ```
94 pub fn load(&self, ordering: Ordering) -> ThreadState{
95 from_raw(self.0.load(ordering))
96 }
97
98 /// Stores a value into the thread state if the current state is the same as
99 /// the `current` state.
100 ///
101 /// The return value is a result indicating whether the new state was written and
102 /// containing the previous state. On success this value is guaranteed to be equal to
103 /// `current`.
104 ///
105 /// `compare_exchange` takes two [`Ordering`] arguments to describe the memory
106 /// ordering of this operation. `success` describes the required ordering for the
107 /// read-modify-write operation that takes place if the comparison with `current` succeeds.
108 /// `failure` describes the required ordering for the load operation that takes place when
109 /// the comparison fails. Using [`Acquire`](`Ordering::Acquire`) as success ordering makes the store part
110 /// of this operation [`Relaxed`](`Ordering::Relaxed`), and using [`Release`](`Ordering::Release`) makes the successful load
111 /// [`Relaxed`](`Ordering::Relaxed`). The failure ordering can only be [`SeqCst`](`Ordering::SeqCst`), [`Acquire`](`Ordering::Acquire`) or [`Relaxed`](`Ordering::Relaxed`).
112 ///
113 /// # Examples
114 ///
115 /// ```
116 /// use kernel_api::threading::{ThreadState, AtomicThreadState};
117 /// use core::sync::atomic::Ordering;
118 ///
119 /// let state = AtomicThreadState::new(ThreadState::Killed(0));
120 ///
121 /// assert_eq!(state.compare_exchange(ThreadState::Killed(0), ThreadState::Running,
122 /// Ordering::Acquire,
123 /// Ordering::Relaxed),
124 /// Ok(ThreadState::Killed(0)));
125 /// assert_eq!(some_var.load(Ordering::Relaxed), ThreadState::Running);
126 ///
127 /// assert_eq!(some_var.compare_exchange(ThreadState::Runnable, ThreadState::Parked,
128 /// Ordering::SeqCst,
129 /// Ordering::Acquire),
130 /// Err(ThreadState::Running));
131 /// assert_eq!(some_var.load(Ordering::Relaxed), ThreadState::Running);
132 /// ```
133 #[expect(clippy::missing_errors_doc, reason = "doesn't make sense in this context")]
134 pub fn compare_exchange(&self, current: ThreadState, new: ThreadState, success: Ordering, failure: Ordering) -> Result<ThreadState, ThreadState> {
135 let current = into_raw(current);
136 let new = into_raw(new);
137 self.0.compare_exchange(current, new, success, failure)
138 .map(from_raw)
139 .map_err(from_raw)
140 }
141
142 /// Fetches the current state, and applies a function to it that returns an optional
143 /// new state. Returns a `Result` of `Ok(previous_state)` if the function returned `Some(_)`, else
144 /// `Err(previous_state)`.
145 ///
146 /// Note: This may call the function multiple times if the value has been changed from other threads in
147 /// the meantime, as long as the function returns `Some(_)`, but the function will have been applied
148 /// only once to the stored value.
149 ///
150 /// `fetch_update` takes two [`Ordering`] arguments to describe the memory ordering of this operation.
151 /// The first describes the required ordering for when the operation finally succeeds while the second
152 /// describes the required ordering for loads. These correspond to the success and failure orderings of
153 /// [`compare_exchange`] respectively.
154 ///
155 /// Using [`Acquire`](`Ordering::Acquire`) as success ordering makes the store part
156 /// of this operation [`Relaxed`](`Ordering::Relaxed`), and using [`Release`](`Ordering::Release`) makes the final successful load
157 /// [`Relaxed`](`Ordering::Relaxed`). The (failed) load ordering can only be [`SeqCst`](`Ordering::SeqCst`), [`Acquire`](`Ordering::Acquire`) or [`Relaxed`](`Ordering::Relaxed`).
158 ///
159 /// # Examples
160 ///
161 /// ```rust
162 /// use kernel_api::threading::{ThreadState, AtomicThreadState};
163 /// use core::sync::atomic::Ordering;
164 ///
165 /// let state = AtomicThreadState::new(ThreadState::Killed(0));
166 /// assert_eq!(state.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(ThreadState::Running));
167 /// assert_eq!(
168 /// state.fetch_update(
169 /// Ordering::SeqCst,
170 /// Ordering::SeqCst,
171 /// |old_state| {
172 /// match old_state {
173 /// ThreadState::Killed(code) => Some(ThreadState::Killed(code + 1)),
174 /// _ => None,
175 /// }
176 /// }
177 /// ),
178 /// Ok(ThreadState::Killed(0))
179 /// );
180 /// assert_eq!(state.load(Ordering::SeqCst), ThreadState::Killed(1));
181 /// ```
182 #[expect(clippy::missing_errors_doc, reason = "doesn't make sense in this context")]
183 pub fn fetch_update(&self, set_order: Ordering, fetch_order: Ordering, mut f: impl FnMut(ThreadState) -> Option<ThreadState>) -> Result<ThreadState, ThreadState> {
184 self.0.fetch_update(set_order, fetch_order, |val| f(from_raw(val)).map(into_raw))
185 .map(from_raw)
186 .map_err(from_raw)
187 }
188
189 /// Returns `true` if the thread is actively running.
190 ///
191 /// # Examples
192 ///
193 /// ```
194 /// use kernel_api::threading::{ThreadState, AtomicThreadState};
195 ///
196 /// let running = AtomicThreadState::new(ThreadState::Running);
197 /// assert!(running.running());
198 ///
199 /// let dead = AtomicThreadState::new(ThreadState::Killed(0));
200 /// assert!(!dead.running());
201 /// ```
202 pub fn running(&self) -> bool {
203 matches!(
204 self.load(Ordering::SeqCst),
205 ThreadState::Running,
206 )
207 }
208
209 /// Returns `true` if the thread could be run in its current state.
210 ///
211 /// # Examples
212 ///
213 /// ```
214 /// use kernel_api::threading::{ThreadState, AtomicThreadState};
215 ///
216 /// let runnable = AtomicThreadState::new(ThreadState::Runnable);
217 /// assert!(runnable.runnable());
218 ///
219 /// let dead = AtomicThreadState::new(ThreadState::Killed(0));
220 /// assert!(!dead.runnable());
221 /// ```
222 pub fn runnable(&self) -> bool {
223 matches!(
224 self.load(Ordering::SeqCst),
225 ThreadState::Running | ThreadState::Ready | ThreadState::NearlyParked,
226 )
227 }
228}
229
230impl Debug for AtomicThreadState {
231 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
232 write!(f, "AtomicThreadState {{ {:?} }}", self.load(Ordering::Relaxed))
233 }
234}
235
236/// The current state of a thread.
237#[derive(Debug, Copy, Clone)]
238#[repr(u8)]
239pub enum ThreadState {
240 /// The thread is able to run, but has not yet been scheduled.
241 Ready = 0,
242 /// The thread is actively running.
243 Running = 1,
244 /// The thread is parked.
245 Parked = 2,
246 /// The thread is in the process of being parked.
247 NearlyParked = 3,
248 /// The thread has exited with a return code and is waiting to be removed from runqueues.
249 Killed(i32) = 4,
250 /// The thread has exited with a return code.
251 Zombie(i32) = 5,
252}