1 //! Thread implementation backed by μITRON tasks. Assumes `acre_tsk` and
2 //! `exd_tsk` are available.
5 error::{expect_success, expect_success_aborting, ItronError},
15 sync::atomic::{AtomicUsize, Ordering},
16 sys::thread_local_dtor::run_dtors,
21 p_inner: NonNull<ThreadInner>,
23 /// The ID of the underlying task.
27 // Safety: There's nothing in `Thread` that ties it to the original creator. It
28 // can be dropped by any threads.
29 unsafe impl Send for Thread {}
30 // Safety: `Thread` provides no methods that take `&self`.
31 unsafe impl Sync for Thread {}
33 /// State data shared between a parent thread and child thread. It's dropped on
34 /// a transition to one of the final states.
36 /// This field is used on thread creation to pass a closure from
37 /// `Thread::new` to the created task.
38 start: UnsafeCell<ManuallyDrop<Box<dyn FnOnce()>>>,
40 /// A state machine. Each transition is annotated with `[...]` in the
45 /// <P>: parent, <C>: child, (?): don't-care
47 /// DETACHED (-1) --------------------> EXITED (?)
54 /// INIT (0) -----------------------> FINISHED (-1)
57 /// | <P>join/slp_tsk | <P>join/del_tsk
58 /// | | <P>detach/del_tsk
61 /// JOINING JOINED (?)
65 /// \ <C>finish/wup_tsk / <P>slp_tsk-complete/ter_tsk
68 /// '--> JOIN_FINALIZE ---'
71 lifecycle: AtomicUsize,
74 // Safety: The only `!Sync` field, `ThreadInner::start`, is only touched by
75 // the task represented by `ThreadInner`.
76 unsafe impl Sync for ThreadInner {}
78 const LIFECYCLE_INIT: usize = 0;
79 const LIFECYCLE_FINISHED: usize = usize::MAX;
80 const LIFECYCLE_DETACHED: usize = usize::MAX;
81 const LIFECYCLE_JOIN_FINALIZE: usize = usize::MAX;
82 const LIFECYCLE_DETACHED_OR_JOINED: usize = usize::MAX;
83 const LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE: usize = usize::MAX;
84 // there's no single value for `JOINING`
86 // 64KiB for 32-bit ISAs, 128KiB for 64-bit ISAs.
87 pub const DEFAULT_MIN_STACK_SIZE: usize = 0x4000 * crate::mem::size_of::<usize>();
92 /// See `thread::Builder::spawn_unchecked` for safety requirements.
93 pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
94 let inner = Box::new(ThreadInner {
95 start: UnsafeCell::new(ManuallyDrop::new(p)),
96 lifecycle: AtomicUsize::new(LIFECYCLE_INIT),
99 unsafe extern "C" fn trampoline(exinf: isize) {
100 let p_inner: *mut ThreadInner = crate::ptr::from_exposed_addr_mut(exinf as usize);
101 // Safety: `ThreadInner` is alive at this point
102 let inner = unsafe { &*p_inner };
104 // Safety: Since `trampoline` is called only once for each
105 // `ThreadInner` and only `trampoline` touches `start`,
106 // `start` contains contents and is safe to mutably borrow.
107 let p = unsafe { ManuallyDrop::take(&mut *inner.start.get()) };
110 // Fix the current thread's state just in case, so that the
111 // destructors won't abort
112 // Safety: Not really unsafe
113 let _ = unsafe { abi::unl_cpu() };
114 let _ = unsafe { abi::ena_dsp() };
116 // Run TLS destructors now because they are not
117 // called automatically for terminated tasks.
118 unsafe { run_dtors() };
120 let old_lifecycle = inner
122 .swap(LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE, Ordering::Release);
124 match old_lifecycle {
125 LIFECYCLE_DETACHED => {
126 // [DETACHED → EXITED]
127 // No one will ever join, so we'll ask the collector task to
130 // In this case, `*p_inner`'s ownership has been moved to
131 // us, and we are responsible for dropping it. The acquire
132 // ordering is not necessary because the parent thread made
133 // no memory access needing synchronization since the call
135 // Safety: See above.
136 let _ = unsafe { Box::from_raw(p_inner) };
138 // Safety: There are no pinned references to the stack
139 unsafe { terminate_and_delete_current_task() };
143 // The parent hasn't decided whether to join or detach this
144 // thread yet. Whichever option the parent chooses,
145 // it'll have to delete this task.
146 // Since the parent might drop `*inner` as soon as it sees
147 // `FINISHED`, the release ordering must be used in the
148 // above `swap` call.
151 // Since the parent might drop `*inner` and terminate us as
152 // soon as it sees `JOIN_FINALIZE`, the release ordering
153 // must be used in the above `swap` call.
155 // [JOINING → JOIN_FINALIZE]
156 // Wake up the parent task.
159 let mut er = abi::wup_tsk(parent_tid as _);
160 if er == abi::E_QOVR {
161 // `E_QOVR` indicates there's already
173 // Safety: `Box::into_raw` returns a non-null pointer
174 let p_inner = unsafe { NonNull::new_unchecked(Box::into_raw(inner)) };
176 let new_task = ItronError::err_if_negative(unsafe {
177 abi::acre_tsk(&abi::T_CTSK {
178 // Activate this task immediately
180 exinf: p_inner.as_ptr().expose_addr() as abi::EXINF,
182 task: Some(trampoline),
183 // Inherit the calling task's base priority
184 itskpri: abi::TPRI_SELF,
186 // Let the kernel allocate the stack,
187 stk: crate::ptr::null_mut(),
190 .map_err(|e| e.as_io_error())?;
192 Ok(Self { p_inner, task: new_task })
196 expect_success(unsafe { abi::rot_rdq(abi::TPRI_SELF) }, &"rot_rdq");
199 pub fn set_name(_name: &CStr) {
203 pub fn sleep(dur: Duration) {
204 for timeout in dur2reltims(dur) {
205 expect_success(unsafe { abi::dly_tsk(timeout) }, &"dly_tsk");
210 // Safety: `ThreadInner` is alive at this point
211 let inner = unsafe { self.p_inner.as_ref() };
212 // Get the current task ID. Panicking here would cause a resource leak,
213 // so just abort on failure.
214 let current_task = task::current_task_id_aborting();
215 debug_assert!(usize::try_from(current_task).is_ok());
216 debug_assert_ne!(current_task as usize, LIFECYCLE_INIT);
217 debug_assert_ne!(current_task as usize, LIFECYCLE_DETACHED);
219 let current_task = current_task as usize;
221 match inner.lifecycle.swap(current_task, Ordering::Acquire) {
224 // The child task will transition the state to `JOIN_FINALIZE`
227 expect_success_aborting(unsafe { abi::slp_tsk() }, &"slp_tsk");
228 // To synchronize with the child task's memory accesses to
229 // `inner` up to the point of the assignment of
230 // `JOIN_FINALIZE`, `Ordering::Acquire` must be used for the
232 if inner.lifecycle.load(Ordering::Acquire) == LIFECYCLE_JOIN_FINALIZE {
237 // [JOIN_FINALIZE → JOINED]
239 LIFECYCLE_FINISHED => {
240 // [FINISHED → JOINED]
241 // To synchronize with the child task's memory accesses to
242 // `inner` up to the point of the assignment of `FINISHED`,
243 // `Ordering::Acquire` must be used for the above `swap` call`.
245 _ => unsafe { hint::unreachable_unchecked() },
248 // Terminate and delete the task
249 // Safety: `self.task` still represents a task we own (because this
250 // method or `detach_inner` is called only once for each
251 // `Thread`). The task indicated that it's safe to delete by
252 // entering the `FINISHED` or `JOIN_FINALIZE` state.
253 unsafe { terminate_and_delete_task(self.task) };
255 // In either case, we are responsible for dropping `inner`.
256 // Safety: The contents of `*p_inner` will not be accessed hereafter
257 let _inner = unsafe { Box::from_raw(self.p_inner.as_ptr()) };
259 // Skip the destructor (because it would attempt to detach the thread)
260 crate::mem::forget(self);
264 impl Drop for Thread {
266 // Safety: `ThreadInner` is alive at this point
267 let inner = unsafe { self.p_inner.as_ref() };
269 // Detach the thread.
270 match inner.lifecycle.swap(LIFECYCLE_DETACHED_OR_JOINED, Ordering::Acquire) {
273 // When the time comes, the child will figure out that no
274 // one will ever join it.
275 // The ownership of `*p_inner` is moved to the child thread.
276 // However, the release ordering is not necessary because we
277 // made no memory access needing synchronization since the call
280 LIFECYCLE_FINISHED => {
281 // [FINISHED → JOINED]
282 // The task has already decided that we should delete the task.
283 // To synchronize with the child task's memory accesses to
284 // `inner` up to the point of the assignment of `FINISHED`,
285 // the acquire ordering is required for the above `swap` call.
287 // Terminate and delete the task
288 // Safety: `self.task` still represents a task we own (because
289 // this method or `join_inner` is called only once for
290 // each `Thread`). The task indicated that it's safe to
291 // delete by entering the `FINISHED` state.
292 unsafe { terminate_and_delete_task(self.task) };
294 // Wwe are responsible for dropping `*p_inner`.
295 // Safety: The contents of `*p_inner` will not be accessed hereafter
296 let _ = unsafe { Box::from_raw(self.p_inner.as_ptr()) };
298 _ => unsafe { hint::unreachable_unchecked() },
305 pub unsafe fn current() -> Option<Guard> {
308 pub unsafe fn init() -> Option<Guard> {
313 /// Terminate and delete the specified task.
315 /// This function will abort if `deleted_task` refers to the calling task.
317 /// It is assumed that the specified task is solely managed by the caller -
318 /// i.e., other threads must not "resuscitate" the specified task or delete it
319 /// prematurely while this function is still in progress. It is allowed for the
320 /// specified task to exit by its own.
324 /// The task must be safe to terminate. This is in general not true
325 /// because there might be pinned references to the task's stack.
326 unsafe fn terminate_and_delete_task(deleted_task: abi::ID) {
327 // Terminate the task
328 // Safety: Upheld by the caller
329 match unsafe { abi::ter_tsk(deleted_task) } {
330 // Indicates the task is already dormant, ignore it
333 expect_success_aborting(er, &"ter_tsk");
338 // Safety: Upheld by the caller
339 expect_success_aborting(unsafe { abi::del_tsk(deleted_task) }, &"del_tsk");
342 /// Terminate and delete the calling task.
344 /// Atomicity is not required - i.e., it can be assumed that other threads won't
345 /// `ter_tsk` the calling task while this function is still in progress. (This
346 /// property makes it easy to implement this operation on μITRON-derived kernels
347 /// that don't support `exd_tsk`.)
351 /// The task must be safe to terminate. This is in general not true
352 /// because there might be pinned references to the task's stack.
353 unsafe fn terminate_and_delete_current_task() -> ! {
354 expect_success_aborting(unsafe { abi::exd_tsk() }, &"exd_tsk");
355 // Safety: `exd_tsk` never returns on success
356 unsafe { crate::hint::unreachable_unchecked() };
359 pub fn available_parallelism() -> io::Result<crate::num::NonZeroUsize> {