ax_task/thread/
execution.rs1use alloc::{boxed::Box, string::String};
3use core::{
4 fmt,
5 sync::atomic::{AtomicBool, AtomicI32, Ordering},
6};
7
8use crate::{
9 runtime::{
10 context::runtime_task_system,
11 delivery::inbox::{InboxKind, InboxNode},
12 lock::PreemptTicketLock,
13 task_runtime,
14 },
15 sync::WaitQueue,
16 thread::{TaskError, ThreadHandle},
17};
18
19#[must_use = "prepare must be published or cancelled"]
24pub struct PreparedThread {
25 handle: Option<ThreadHandle>,
26}
27impl PreparedThread {
28 pub(crate) fn new(handle: ThreadHandle) -> Self {
29 Self {
30 handle: Some(handle),
31 }
32 }
33 pub fn thread_handle(&self) -> ThreadHandle {
35 self.handle
36 .as_ref()
37 .expect("unconsumed preparation")
38 .clone()
39 }
40 pub fn stage(mut self) -> Result<StagedThread, TaskError> {
42 let handle = self.handle.as_ref().expect("unconsumed preparation");
43 runtime_task_system()?.stage_new_thread(handle)?;
44 Ok(StagedThread {
45 handle: self.handle.take(),
46 })
47 }
48 pub fn publish(self) -> Result<ThreadHandle, TaskError> {
50 Ok(self.stage()?.activate())
51 }
52}
53impl Drop for PreparedThread {
54 fn drop(&mut self) {
55 if let Some(handle) = self.handle.take() {
56 cancel_new_thread(handle);
57 }
58 }
59}
60
61#[must_use = "staged publication must be activated or cancelled"]
66pub struct StagedThread {
67 handle: Option<ThreadHandle>,
68}
69impl StagedThread {
70 pub fn thread_handle(&self) -> ThreadHandle {
72 self.handle.as_ref().expect("unconsumed stage").clone()
73 }
74 pub fn activate(mut self) -> ThreadHandle {
76 let mut irq = crate::runtime::context::RuntimeIrqGuard::enter();
77 let mut cpu = crate::runtime::context::runtime_current_cpu_mut(&mut irq)
78 .expect("activation requires an installed owner CPU");
79 let handle = self.handle.as_ref().expect("unconsumed stage");
80 runtime_task_system()
81 .expect("staged system remains installed")
82 .activate_staged_thread(cpu.as_mut(), handle);
83 self.handle.take().expect("committed stage")
86 }
87}
88impl Drop for StagedThread {
89 fn drop(&mut self) {
90 if let Some(handle) = self.handle.take() {
91 cancel_new_thread(handle);
92 }
93 }
94}
95
96pub(crate) struct ThreadExecution {
97 pub(crate) cancellation_node: InboxNode,
98 entry: PreemptTicketLock<Option<Box<dyn FnOnce() + Send + 'static>>>,
99 completion: WaitQueue,
100 completed: AtomicBool,
101 exit_code: AtomicI32,
102 name: String,
103}
104impl fmt::Debug for ThreadExecution {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 f.debug_struct("ThreadExecution")
107 .field("name", &self.name)
108 .finish_non_exhaustive()
109 }
110}
111impl ThreadExecution {
112 pub(crate) fn new(entry: Box<dyn FnOnce() + Send + 'static>, name: String) -> Self {
113 Self {
114 cancellation_node: InboxNode::new(InboxKind::Reclaim),
115 entry: PreemptTicketLock::new(Some(entry)),
116 completion: WaitQueue::new(),
117 completed: AtomicBool::new(false),
118 exit_code: AtomicI32::new(0),
119 name,
120 }
121 }
122 pub(crate) fn finish(&self) {
123 let unused_entry = self.entry.lock().take();
126 drop(unused_entry);
127 if !self.completed.swap(true, Ordering::AcqRel) {
128 self.completion.notify_all();
129 }
130 }
131}
132
133impl ThreadHandle {
134 pub fn extension(&self) -> Option<crate::thread::ThreadExtensionBorrow<'_>> {
136 self.extension_view()
137 .map(|view| crate::thread::ThreadExtensionBorrow::new(view, self))
138 }
139
140 pub fn wait(&self) -> Result<i32, TaskError> {
142 if crate::thread::current::current_thread_id()? == self.id() {
143 return Err(TaskError::InvalidConfiguration);
144 }
145 let execution = self
146 .core
147 .execution
148 .as_ref()
149 .ok_or(TaskError::InvalidConfiguration)?;
150 execution
151 .completion
152 .try_wait_until(|| execution.completed.load(Ordering::Acquire))?;
153 Ok(execution.exit_code.load(Ordering::Acquire))
154 }
155 pub fn join(self) -> Result<i32, TaskError> {
157 let code = self.wait()?;
158 match runtime_task_system()?.reap_thread_handle(self) {
159 Ok(()) => (),
160 Err(error)
161 if matches!(
162 error.task_error(),
163 TaskError::ThreadBusy | TaskError::NotExited
164 ) =>
165 {
166 drop(error.into_retry_handle())
167 }
168 Err(error) => return Err(error.task_error()),
169 }
170 Ok(code)
171 }
172 pub fn detach(self) {
174 drop(self);
175 }
176}
177
178pub fn exit_current(exit_code: i32) -> ! {
180 let permit = crate::thread::current::prepare_current_exit()
181 .unwrap_or_else(|error| task_runtime::fatal_invariant(15, error_code(error)));
182 let core = crate::thread::current::current_thread_core_arc()
183 .unwrap_or_else(|error| task_runtime::fatal_invariant(10, error_code(error)));
184 if let Some(execution) = core.execution.as_ref() {
185 execution.exit_code.store(exit_code, Ordering::Relaxed);
186 execution.finish();
187 }
188 drop(core);
189 crate::thread::current::commit_current_exit(permit)
190}
191
192pub(crate) unsafe extern "C" fn thread_entry() -> ! {
193 unsafe { crate::runtime::switch::finish_initial_context_switch() }
195 .unwrap_or_else(|error| task_runtime::fatal_invariant(9, error_code(error)));
196 let core = crate::thread::current::current_thread_core_arc()
197 .unwrap_or_else(|error| task_runtime::fatal_invariant(10, error_code(error)));
198 let entry = core
199 .execution
200 .as_ref()
201 .expect("thread entry requires execution state")
202 .entry
203 .lock()
204 .take()
205 .expect("thread entry runs once");
206 drop(core);
208 entry();
209 exit_current(0)
210}
211
212fn cancel_new_thread(handle: ThreadHandle) {
213 let system = runtime_task_system().expect("prepared task system remains installed");
214 system.publish_thread_cancellation(&handle.core);
215 drop(handle);
216}
217
218const fn error_code(error: TaskError) -> usize {
219 match error {
220 TaskError::NotInitialized => 1,
221 TaskError::InvalidRuntimeHandle => 2,
222 TaskError::NoRunnableThread => 3,
223 TaskError::UnsafeContext => 4,
224 _ => 255,
225 }
226}