1use core::sync::atomic::{AtomicU64, Ordering};
4#[cfg(not(feature = "kernel"))]
5use core::time::Duration;
6
7use twizzler_rt_abi::marker::BaseType;
8
9#[cfg(not(feature = "kernel"))]
10use crate::syscall::*;
11use crate::syscall::{ThreadSyncFlags, ThreadSyncOp, ThreadSyncReference, ThreadSyncSleep};
12#[allow(unused_imports)]
13use crate::{
14 object::{ObjID, Protections},
15 syscall::{MapFlags, ThreadSpawnArgs, ThreadSpawnFlags},
16};
17
18pub mod event;
19#[derive(Default)]
21#[repr(C)]
22pub struct ThreadRepr {
23 version: u32,
24 flags: u32,
25 #[cfg(not(feature = "kernel"))]
26 status: AtomicU64,
27 #[cfg(feature = "kernel")]
28 pub status: AtomicU64,
29 code: AtomicU64,
30}
31
32impl BaseType for ThreadRepr {}
33
34#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Ord, Eq, Hash)]
44#[repr(u8)]
45pub enum ExecutionState {
46 Running,
48 Sleeping,
50 Suspended,
52 Exited = 255,
54}
55
56impl ExecutionState {
57 pub fn from_status(status: u64) -> Self {
58 match status & 0xff {
60 1 => ExecutionState::Sleeping,
61 2 => ExecutionState::Suspended,
62 255 => ExecutionState::Exited,
63 _ => ExecutionState::Running,
64 }
65 }
66
67 pub fn to_status(&self) -> u64 {
68 match self {
69 ExecutionState::Running => 0,
70 ExecutionState::Sleeping => 1,
71 ExecutionState::Suspended => 2,
72 ExecutionState::Exited => 255,
73 }
74 }
75}
76
77impl ThreadRepr {
78 pub fn get_state(&self) -> ExecutionState {
79 let status = self.status.load(Ordering::Acquire);
80 ExecutionState::from_status(status)
81 }
82
83 pub fn get_code(&self) -> u64 {
84 self.code.load(Ordering::SeqCst)
85 }
86
87 pub fn set_state(&self, state: ExecutionState, code: u64) -> ExecutionState {
88 let mut old_status = self.status.load(Ordering::SeqCst);
89 loop {
90 let old_state = ExecutionState::from_status(old_status);
91 if old_state == ExecutionState::Exited {
92 return old_state;
93 }
94
95 let status = state as u8 as u64;
96 if state == ExecutionState::Exited {
97 self.code.store(code, Ordering::SeqCst);
98 }
99
100 let result = self.status.compare_exchange(
101 old_status,
102 status,
103 Ordering::SeqCst,
104 Ordering::SeqCst,
105 );
106 match result {
107 Ok(_) => {
108 if !(old_state == ExecutionState::Running && state == ExecutionState::Sleeping
109 || old_state == ExecutionState::Sleeping
110 && state == ExecutionState::Running)
111 && old_state != state
112 {
113 #[cfg(not(feature = "kernel"))]
114 let _ = sys_thread_sync(
115 &mut [ThreadSync::new_wake(ThreadSyncWake::new(
116 ThreadSyncReference::Virtual(&self.status),
117 usize::MAX,
118 ))],
119 None,
120 );
121 }
122 return old_state;
123 }
124 Err(x) => {
125 old_status = x;
126 }
127 }
128 }
129 }
130
131 pub fn waitable(&self, state: ExecutionState) -> ThreadSyncSleep {
133 ThreadSyncSleep::new(
134 ThreadSyncReference::Virtual(&self.status),
135 state as u64,
136 ThreadSyncOp::Equal,
137 ThreadSyncFlags::INVERT,
138 )
139 }
140
141 pub fn waitable_until_not(&self, state: ExecutionState) -> ThreadSyncSleep {
143 ThreadSyncSleep::new(
144 ThreadSyncReference::Virtual(&self.status),
145 state as u64,
146 ThreadSyncOp::Equal,
147 ThreadSyncFlags::empty(),
148 )
149 }
150
151 #[cfg(not(feature = "kernel"))]
152 pub fn wait(
155 &self,
156 expected: ExecutionState,
157 timeout: Option<Duration>,
158 ) -> Option<(ExecutionState, u64)> {
159 let mut status = self.get_state();
160 loop {
161 if status != expected {
162 return Some((status, self.code.load(Ordering::SeqCst)));
163 }
164 let op = self.waitable_until_not(expected);
165 sys_thread_sync(&mut [ThreadSync::new_sleep(op)], timeout).unwrap();
166 status = self.get_state();
167 if timeout.is_some() && status == expected {
168 return None;
169 }
170 }
171 }
172
173 #[cfg(not(feature = "kernel"))]
174 pub fn wait_until(
177 &self,
178 target: ExecutionState,
179 timeout: Option<Duration>,
180 ) -> Option<(ExecutionState, u64)> {
181 let mut status = self.get_state();
182 loop {
183 if status == target {
184 return Some((status, self.code.load(Ordering::SeqCst)));
185 }
186 let op = self.waitable(target);
187 sys_thread_sync(&mut [ThreadSync::new_sleep(op)], timeout).unwrap();
188 status = self.get_state();
189 if timeout.is_some() && status != target {
190 return None;
191 }
192 }
193 }
194}