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
::AcqRel
);
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 ensures that the swap operation that wrote
133 // `LIFECYCLE_DETACHED` happens-before `Box::from_raw(
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 // To make the task referred to by `parent_tid` visible, we
156 // must use the acquire ordering in the above `swap` call.
158 // [JOINING → JOIN_FINALIZE]
159 // Wake up the parent task.
162 let mut er
= abi
::wup_tsk(parent_tid
as _
);
163 if er
== abi
::E_QOVR
{
164 // `E_QOVR` indicates there's already
176 // Safety: `Box::into_raw` returns a non-null pointer
177 let p_inner
= unsafe { NonNull::new_unchecked(Box::into_raw(inner)) }
;
179 let new_task
= ItronError
::err_if_negative(unsafe {
180 abi
::acre_tsk(&abi
::T_CTSK
{
181 // Activate this task immediately
183 exinf
: p_inner
.as_ptr().expose_addr() as abi
::EXINF
,
185 task
: Some(trampoline
),
186 // Inherit the calling task's base priority
187 itskpri
: abi
::TPRI_SELF
,
189 // Let the kernel allocate the stack,
190 stk
: crate::ptr
::null_mut(),
193 .map_err(|e
| e
.as_io_error())?
;
195 Ok(Self { p_inner, task: new_task }
)
199 expect_success(unsafe { abi::rot_rdq(abi::TPRI_SELF) }
, &"rot_rdq");
202 pub fn set_name(_name
: &CStr
) {
206 pub fn sleep(dur
: Duration
) {
207 for timeout
in dur2reltims(dur
) {
208 expect_success(unsafe { abi::dly_tsk(timeout) }
, &"dly_tsk");
213 // Safety: `ThreadInner` is alive at this point
214 let inner
= unsafe { self.p_inner.as_ref() }
;
215 // Get the current task ID. Panicking here would cause a resource leak,
216 // so just abort on failure.
217 let current_task
= task
::current_task_id_aborting();
218 debug_assert
!(usize::try_from(current_task
).is_ok());
219 debug_assert_ne
!(current_task
as usize, LIFECYCLE_INIT
);
220 debug_assert_ne
!(current_task
as usize, LIFECYCLE_DETACHED
);
222 let current_task
= current_task
as usize;
224 match inner
.lifecycle
.swap(current_task
, Ordering
::AcqRel
) {
227 // The child task will transition the state to `JOIN_FINALIZE`
230 // To make the task referred to by `current_task` visible from
231 // the child task's point of view, we must use the release
232 // ordering in the above `swap` call.
234 expect_success_aborting(unsafe { abi::slp_tsk() }
, &"slp_tsk");
235 // To synchronize with the child task's memory accesses to
236 // `inner` up to the point of the assignment of
237 // `JOIN_FINALIZE`, `Ordering::Acquire` must be used for the
239 if inner
.lifecycle
.load(Ordering
::Acquire
) == LIFECYCLE_JOIN_FINALIZE
{
244 // [JOIN_FINALIZE → JOINED]
246 LIFECYCLE_FINISHED
=> {
247 // [FINISHED → JOINED]
248 // To synchronize with the child task's memory accesses to
249 // `inner` up to the point of the assignment of `FINISHED`,
250 // `Ordering::Acquire` must be used for the above `swap` call.
252 _
=> unsafe { hint::unreachable_unchecked() }
,
255 // Terminate and delete the task
256 // Safety: `self.task` still represents a task we own (because this
257 // method or `detach_inner` is called only once for each
258 // `Thread`). The task indicated that it's safe to delete by
259 // entering the `FINISHED` or `JOIN_FINALIZE` state.
260 unsafe { terminate_and_delete_task(self.task) }
;
262 // In either case, we are responsible for dropping `inner`.
263 // Safety: The contents of `*p_inner` will not be accessed hereafter
264 let _inner
= unsafe { Box::from_raw(self.p_inner.as_ptr()) }
;
266 // Skip the destructor (because it would attempt to detach the thread)
267 crate::mem
::forget(self);
271 impl Drop
for Thread
{
273 // Safety: `ThreadInner` is alive at this point
274 let inner
= unsafe { self.p_inner.as_ref() }
;
276 // Detach the thread.
277 match inner
.lifecycle
.swap(LIFECYCLE_DETACHED_OR_JOINED
, Ordering
::AcqRel
) {
280 // When the time comes, the child will figure out that no
281 // one will ever join it.
282 // The ownership of `*p_inner` is moved to the child thread.
283 // The release ordering ensures that the above swap operation on
284 // `lifecycle` happens-before the child thread's
285 // `Box::from_raw(p_inner)`.
287 LIFECYCLE_FINISHED
=> {
288 // [FINISHED → JOINED]
289 // The task has already decided that we should delete the task.
290 // To synchronize with the child task's memory accesses to
291 // `inner` up to the point of the assignment of `FINISHED`,
292 // the acquire ordering is required for the above `swap` call.
294 // Terminate and delete the task
295 // Safety: `self.task` still represents a task we own (because
296 // this method or `join_inner` is called only once for
297 // each `Thread`). The task indicated that it's safe to
298 // delete by entering the `FINISHED` state.
299 unsafe { terminate_and_delete_task(self.task) }
;
301 // Wwe are responsible for dropping `*p_inner`.
302 // Safety: The contents of `*p_inner` will not be accessed hereafter
303 let _
= unsafe { Box::from_raw(self.p_inner.as_ptr()) }
;
305 _
=> unsafe { hint::unreachable_unchecked() }
,
312 pub unsafe fn current() -> Option
<Guard
> {
315 pub unsafe fn init() -> Option
<Guard
> {
320 /// Terminate and delete the specified task.
322 /// This function will abort if `deleted_task` refers to the calling task.
324 /// It is assumed that the specified task is solely managed by the caller -
325 /// i.e., other threads must not "resuscitate" the specified task or delete it
326 /// prematurely while this function is still in progress. It is allowed for the
327 /// specified task to exit by its own.
331 /// The task must be safe to terminate. This is in general not true
332 /// because there might be pinned references to the task's stack.
333 unsafe fn terminate_and_delete_task(deleted_task
: abi
::ID
) {
334 // Terminate the task
335 // Safety: Upheld by the caller
336 match unsafe { abi::ter_tsk(deleted_task) }
{
337 // Indicates the task is already dormant, ignore it
340 expect_success_aborting(er
, &"ter_tsk");
345 // Safety: Upheld by the caller
346 expect_success_aborting(unsafe { abi::del_tsk(deleted_task) }
, &"del_tsk");
349 /// Terminate and delete the calling task.
351 /// Atomicity is not required - i.e., it can be assumed that other threads won't
352 /// `ter_tsk` the calling task while this function is still in progress. (This
353 /// property makes it easy to implement this operation on μITRON-derived kernels
354 /// that don't support `exd_tsk`.)
358 /// The task must be safe to terminate. This is in general not true
359 /// because there might be pinned references to the task's stack.
360 unsafe fn terminate_and_delete_current_task() -> ! {
361 expect_success_aborting(unsafe { abi::exd_tsk() }
, &"exd_tsk");
362 // Safety: `exd_tsk` never returns on success
363 unsafe { crate::hint::unreachable_unchecked() }
;
366 pub fn available_parallelism() -> io
::Result
<crate::num
::NonZeroUsize
> {