twizzler_abi/
thread.rs

1//! Functions for manipulating threads.
2
3use core::sync::atomic::{AtomicU64, Ordering};
4#[cfg(not(feature = "kernel"))]
5use core::time::Duration;
6
7#[cfg(not(feature = "kernel"))]
8use crate::syscall::*;
9use crate::syscall::{ThreadSyncFlags, ThreadSyncOp, ThreadSyncReference, ThreadSyncSleep};
10#[allow(unused_imports)]
11use crate::{
12    object::{ObjID, Protections},
13    syscall::{MapFlags, ThreadSpawnArgs, ThreadSpawnFlags},
14};
15
16pub mod event;
17/// Base type for a thread object.
18#[derive(Default)]
19#[repr(C)]
20pub struct ThreadRepr {
21    version: u32,
22    flags: u32,
23    #[cfg(not(feature = "kernel"))]
24    status: AtomicU64,
25    #[cfg(feature = "kernel")]
26    pub status: AtomicU64,
27    code: AtomicU64,
28}
29
30/// Possible execution states for a thread. The transitions available are:
31/// +------------+     +-----------+     +-------------+
32/// |  Sleeping  +<--->+  Running  +<--->+  Suspended  |
33/// +------------+     +-----+-----+     +-------------+
34///                          |
35///                          |   +----------+
36///                          +-->+  Exited  |
37///                              +----------+
38/// The kernel will not transition a thread out of the exited state.
39#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Ord, Eq, Hash)]
40#[repr(u8)]
41pub enum ExecutionState {
42    /// The thread is running or waiting to be scheduled on a CPU.
43    Running,
44    /// The thread is sleeping, waiting for a condition in-kernel.
45    Sleeping,
46    /// The thread is suspended, and will not resume until manually transitioned back to running.
47    Suspended,
48    /// The thread has terminated, and will never run again.
49    Exited = 255,
50}
51
52impl ExecutionState {
53    pub fn from_status(status: u64) -> Self {
54        // If we see a status we don't understand, just assume the thread is running.
55        match status & 0xff {
56            1 => ExecutionState::Sleeping,
57            2 => ExecutionState::Suspended,
58            255 => ExecutionState::Exited,
59            _ => ExecutionState::Running,
60        }
61    }
62
63    pub fn to_status(&self) -> u64 {
64        match self {
65            ExecutionState::Running => 0,
66            ExecutionState::Sleeping => 1,
67            ExecutionState::Suspended => 2,
68            ExecutionState::Exited => 255,
69        }
70    }
71}
72
73impl ThreadRepr {
74    pub fn get_state(&self) -> ExecutionState {
75        let status = self.status.load(Ordering::Acquire);
76        ExecutionState::from_status(status)
77    }
78
79    pub fn get_code(&self) -> u64 {
80        self.code.load(Ordering::SeqCst)
81    }
82
83    pub fn set_state(&self, state: ExecutionState, code: u64) -> ExecutionState {
84        let mut old_status = self.status.load(Ordering::SeqCst);
85        loop {
86            let old_state = ExecutionState::from_status(old_status);
87            if old_state == ExecutionState::Exited {
88                return old_state;
89            }
90
91            let status = state as u8 as u64;
92            if state == ExecutionState::Exited {
93                self.code.store(code, Ordering::SeqCst);
94            }
95
96            let result = self.status.compare_exchange(
97                old_status,
98                status,
99                Ordering::SeqCst,
100                Ordering::SeqCst,
101            );
102            match result {
103                Ok(_) => {
104                    if !(old_state == ExecutionState::Running && state == ExecutionState::Sleeping
105                        || old_state == ExecutionState::Sleeping
106                            && state == ExecutionState::Running)
107                        && old_state != state
108                    {
109                        #[cfg(not(feature = "kernel"))]
110                        let _ = sys_thread_sync(
111                            &mut [ThreadSync::new_wake(ThreadSyncWake::new(
112                                ThreadSyncReference::Virtual(&self.status),
113                                usize::MAX,
114                            ))],
115                            None,
116                        );
117                    }
118                    return old_state;
119                }
120                Err(x) => {
121                    old_status = x;
122                }
123            }
124        }
125    }
126
127    /// Create a [ThreadSyncSleep] that will wait until the thread's state matches `state`.
128    pub fn waitable(&self, state: ExecutionState) -> ThreadSyncSleep {
129        ThreadSyncSleep::new(
130            ThreadSyncReference::Virtual(&self.status),
131            state as u64,
132            ThreadSyncOp::Equal,
133            ThreadSyncFlags::INVERT,
134        )
135    }
136
137    /// Create a [ThreadSyncSleep] that will wait until the thread's state is _not_ `state`.
138    pub fn waitable_until_not(&self, state: ExecutionState) -> ThreadSyncSleep {
139        ThreadSyncSleep::new(
140            ThreadSyncReference::Virtual(&self.status),
141            state as u64,
142            ThreadSyncOp::Equal,
143            ThreadSyncFlags::empty(),
144        )
145    }
146
147    #[cfg(not(feature = "kernel"))]
148    /// Wait for a thread's status to change, optionally timing out. Return value is None if timeout
149    /// occurs, or Some((ExecutionState, code)) otherwise.
150    pub fn wait(
151        &self,
152        expected: ExecutionState,
153        timeout: Option<Duration>,
154    ) -> Option<(ExecutionState, u64)> {
155        let mut status = self.get_state();
156        loop {
157            if status != expected {
158                return Some((status, self.code.load(Ordering::SeqCst)));
159            }
160            let op = self.waitable_until_not(expected);
161            sys_thread_sync(&mut [ThreadSync::new_sleep(op)], timeout).unwrap();
162            status = self.get_state();
163            if timeout.is_some() && status == expected {
164                return None;
165            }
166        }
167    }
168
169    #[cfg(not(feature = "kernel"))]
170    /// Wait for a thread's status reach a target value, or exited, optionally timing out. The
171    /// actual execution state of the thread is returned.
172    pub fn wait_until(
173        &self,
174        target: ExecutionState,
175        timeout: Option<Duration>,
176    ) -> Option<(ExecutionState, u64)> {
177        let mut status = self.get_state();
178        loop {
179            if status == target {
180                return Some((status, self.code.load(Ordering::SeqCst)));
181            }
182            let op = self.waitable(target);
183            sys_thread_sync(&mut [ThreadSync::new_sleep(op)], timeout).unwrap();
184            status = self.get_state();
185            if timeout.is_some() && status != target {
186                return None;
187            }
188        }
189    }
190}