1 //! Thread implementation backed by μITRON tasks. Assumes `acre_tsk` and
2 //! `exd_tsk` are available.
5 error::{expect_success, expect_success_aborting, ItronError},
14 sync::atomic::{AtomicUsize, Ordering},
15 sys::thread_local_dtor::run_dtors,
20 inner: ManuallyDrop<Box<ThreadInner>>,
22 /// The ID of the underlying task.
26 /// State data shared between a parent thread and child thread. It's dropped on
27 /// a transition to one of the final states.
29 /// This field is used on thread creation to pass a closure from
30 /// `Thread::new` to the created task.
31 start: UnsafeCell<ManuallyDrop<Box<dyn FnOnce()>>>,
33 /// A state machine. Each transition is annotated with `[...]` in the
38 /// <P>: parent, <C>: child, (?): don't-care
40 /// DETACHED (-1) --------------------> EXITED (?)
47 /// INIT (0) -----------------------> FINISHED (-1)
50 /// | <P>join/slp_tsk | <P>join/del_tsk
51 /// | | <P>detach/del_tsk
54 /// JOINING JOINED (?)
58 /// \ <C>finish/wup_tsk / <P>slp_tsk-complete/ter_tsk
61 /// '--> JOIN_FINALIZE ---'
64 lifecycle: AtomicUsize,
67 // Safety: The only `!Sync` field, `ThreadInner::start`, is only touched by
68 // the task represented by `ThreadInner`.
69 unsafe impl Sync for ThreadInner {}
71 const LIFECYCLE_INIT: usize = 0;
72 const LIFECYCLE_FINISHED: usize = usize::MAX;
73 const LIFECYCLE_DETACHED: usize = usize::MAX;
74 const LIFECYCLE_JOIN_FINALIZE: usize = usize::MAX;
75 const LIFECYCLE_DETACHED_OR_JOINED: usize = usize::MAX;
76 const LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE: usize = usize::MAX;
77 // there's no single value for `JOINING`
79 // 64KiB for 32-bit ISAs, 128KiB for 64-bit ISAs.
80 pub const DEFAULT_MIN_STACK_SIZE: usize = 0x4000 * crate::mem::size_of::<usize>();
85 /// See `thread::Builder::spawn_unchecked` for safety requirements.
86 pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
87 let inner = Box::new(ThreadInner {
88 start: UnsafeCell::new(ManuallyDrop::new(p)),
89 lifecycle: AtomicUsize::new(LIFECYCLE_INIT),
92 unsafe extern "C" fn trampoline(exinf: isize) {
93 // Safety: `ThreadInner` is alive at this point
94 let inner = unsafe { &*(exinf as *const ThreadInner) };
96 // Safety: Since `trampoline` is called only once for each
97 // `ThreadInner` and only `trampoline` touches `start`,
98 // `start` contains contents and is safe to mutably borrow.
99 let p = unsafe { ManuallyDrop::take(&mut *inner.start.get()) };
102 // Fix the current thread's state just in case, so that the
103 // destructors won't abort
104 // Safety: Not really unsafe
105 let _ = unsafe { abi::unl_cpu() };
106 let _ = unsafe { abi::ena_dsp() };
108 // Run TLS destructors now because they are not
109 // called automatically for terminated tasks.
110 unsafe { run_dtors() };
112 let old_lifecycle = inner
114 .swap(LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE, Ordering::Release);
116 match old_lifecycle {
117 LIFECYCLE_DETACHED => {
118 // [DETACHED → EXITED]
119 // No one will ever join, so we'll ask the collector task to
122 // In this case, `inner`'s ownership has been moved to us,
123 // And we are responsible for dropping it. The acquire
124 // ordering is not necessary because the parent thread made
125 // no memory access needing synchronization since the call
127 // Safety: See above.
128 let _ = unsafe { Box::from_raw(inner as *const _ as *mut ThreadInner) };
130 // Safety: There are no pinned references to the stack
131 unsafe { terminate_and_delete_current_task() };
135 // The parent hasn't decided whether to join or detach this
136 // thread yet. Whichever option the parent chooses,
137 // it'll have to delete this task.
138 // Since the parent might drop `*inner` as soon as it sees
139 // `FINISHED`, the release ordering must be used in the
140 // above `swap` call.
143 // Since the parent might drop `*inner` and terminate us as
144 // soon as it sees `JOIN_FINALIZE`, the release ordering
145 // must be used in the above `swap` call.
147 // [JOINING → JOIN_FINALIZE]
148 // Wake up the parent task.
151 let mut er = abi::wup_tsk(parent_tid as _);
152 if er == abi::E_QOVR {
153 // `E_QOVR` indicates there's already
165 let inner_ptr = (&*inner) as *const ThreadInner;
167 let new_task = ItronError::err_if_negative(unsafe {
168 abi::acre_tsk(&abi::T_CTSK {
169 // Activate this task immediately
171 exinf: inner_ptr as abi::EXINF,
173 task: Some(trampoline),
174 // Inherit the calling task's base priority
175 itskpri: abi::TPRI_SELF,
177 // Let the kernel allocate the stack,
178 stk: crate::ptr::null_mut(),
181 .map_err(|e| e.as_io_error())?;
183 Ok(Self { inner: ManuallyDrop::new(inner), task: new_task })
187 expect_success(unsafe { abi::rot_rdq(abi::TPRI_SELF) }, &"rot_rdq");
190 pub fn set_name(_name: &CStr) {
194 pub fn sleep(dur: Duration) {
195 for timeout in dur2reltims(dur) {
196 expect_success(unsafe { abi::dly_tsk(timeout) }, &"dly_tsk");
200 pub fn join(mut self) {
201 let inner = &*self.inner;
202 // Get the current task ID. Panicking here would cause a resource leak,
203 // so just abort on failure.
204 let current_task = task::current_task_id_aborting();
205 debug_assert!(usize::try_from(current_task).is_ok());
206 debug_assert_ne!(current_task as usize, LIFECYCLE_INIT);
207 debug_assert_ne!(current_task as usize, LIFECYCLE_DETACHED);
209 let current_task = current_task as usize;
211 match inner.lifecycle.swap(current_task, Ordering::Acquire) {
214 // The child task will transition the state to `JOIN_FINALIZE`
217 expect_success_aborting(unsafe { abi::slp_tsk() }, &"slp_tsk");
218 // To synchronize with the child task's memory accesses to
219 // `inner` up to the point of the assignment of
220 // `JOIN_FINALIZE`, `Ordering::Acquire` must be used for the
222 if inner.lifecycle.load(Ordering::Acquire) == LIFECYCLE_JOIN_FINALIZE {
227 // [JOIN_FINALIZE → JOINED]
229 LIFECYCLE_FINISHED => {
230 // [FINISHED → JOINED]
231 // To synchronize with the child task's memory accesses to
232 // `inner` up to the point of the assignment of `FINISHED`,
233 // `Ordering::Acquire` must be used for the above `swap` call`.
235 _ => unsafe { hint::unreachable_unchecked() },
238 // Terminate and delete the task
239 // Safety: `self.task` still represents a task we own (because this
240 // method or `detach_inner` is called only once for each
241 // `Thread`). The task indicated that it's safe to delete by
242 // entering the `FINISHED` or `JOIN_FINALIZE` state.
243 unsafe { terminate_and_delete_task(self.task) };
245 // In either case, we are responsible for dropping `inner`.
246 // Safety: The contents of `self.inner` will not be accessed hereafter
247 let _inner = unsafe { ManuallyDrop::take(&mut self.inner) };
249 // Skip the destructor (because it would attempt to detach the thread)
250 crate::mem::forget(self);
254 impl Drop for Thread {
256 // Detach the thread.
257 match self.inner.lifecycle.swap(LIFECYCLE_DETACHED_OR_JOINED, Ordering::Acquire) {
260 // When the time comes, the child will figure out that no
261 // one will ever join it.
262 // The ownership of `self.inner` is moved to the child thread.
263 // However, the release ordering is not necessary because we
264 // made no memory access needing synchronization since the call
267 LIFECYCLE_FINISHED => {
268 // [FINISHED → JOINED]
269 // The task has already decided that we should delete the task.
270 // To synchronize with the child task's memory accesses to
271 // `inner` up to the point of the assignment of `FINISHED`,
272 // the acquire ordering is required for the above `swap` call.
274 // Terminate and delete the task
275 // Safety: `self.task` still represents a task we own (because
276 // this method or `join_inner` is called only once for
277 // each `Thread`). The task indicated that it's safe to
278 // delete by entering the `FINISHED` state.
279 unsafe { terminate_and_delete_task(self.task) };
281 // Wwe are responsible for dropping `inner`.
282 // Safety: The contents of `self.inner` will not be accessed
284 unsafe { ManuallyDrop::drop(&mut self.inner) };
286 _ => unsafe { hint::unreachable_unchecked() },
293 pub unsafe fn current() -> Option<Guard> {
296 pub unsafe fn init() -> Option<Guard> {
301 /// Terminate and delete the specified task.
303 /// This function will abort if `deleted_task` refers to the calling task.
305 /// It is assumed that the specified task is solely managed by the caller -
306 /// i.e., other threads must not "resuscitate" the specified task or delete it
307 /// prematurely while this function is still in progress. It is allowed for the
308 /// specified task to exit by its own.
312 /// The task must be safe to terminate. This is in general not true
313 /// because there might be pinned references to the task's stack.
314 unsafe fn terminate_and_delete_task(deleted_task: abi::ID) {
315 // Terminate the task
316 // Safety: Upheld by the caller
317 match unsafe { abi::ter_tsk(deleted_task) } {
318 // Indicates the task is already dormant, ignore it
321 expect_success_aborting(er, &"ter_tsk");
326 // Safety: Upheld by the caller
327 expect_success_aborting(unsafe { abi::del_tsk(deleted_task) }, &"del_tsk");
330 /// Terminate and delete the calling task.
332 /// Atomicity is not required - i.e., it can be assumed that other threads won't
333 /// `ter_tsk` the calling task while this function is still in progress. (This
334 /// property makes it easy to implement this operation on μITRON-derived kernels
335 /// that don't support `exd_tsk`.)
339 /// The task must be safe to terminate. This is in general not true
340 /// because there might be pinned references to the task's stack.
341 unsafe fn terminate_and_delete_current_task() -> ! {
342 expect_success_aborting(unsafe { abi::exd_tsk() }, &"exd_tsk");
343 // Safety: `exd_tsk` never returns on success
344 unsafe { crate::hint::unreachable_unchecked() };
347 pub fn available_parallelism() -> io::Result<crate::num::NonZeroUsize> {