]> git.lizzy.rs Git - rust.git/blob - library/std/src/sys/itron/thread.rs
Rollup merge of #101648 - Timmmm:home_dir_docs, r=joshtriplett
[rust.git] / library / std / src / sys / itron / thread.rs
1 //! Thread implementation backed by μITRON tasks. Assumes `acre_tsk` and
2 //! `exd_tsk` are available.
3 use super::{
4     abi,
5     error::{expect_success, expect_success_aborting, ItronError},
6     task,
7     time::dur2reltims,
8 };
9 use crate::{
10     cell::UnsafeCell,
11     ffi::CStr,
12     hint, io,
13     mem::ManuallyDrop,
14     ptr::NonNull,
15     sync::atomic::{AtomicUsize, Ordering},
16     sys::thread_local_dtor::run_dtors,
17     time::Duration,
18 };
19
20 pub struct Thread {
21     p_inner: NonNull<ThreadInner>,
22
23     /// The ID of the underlying task.
24     task: abi::ID,
25 }
26
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 {}
32
33 /// State data shared between a parent thread and child thread. It's dropped on
34 /// a transition to one of the final states.
35 struct ThreadInner {
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()>>>,
39
40     /// A state machine. Each transition is annotated with `[...]` in the
41     /// source code.
42     ///
43     /// ```text
44     ///
45     ///    <P>: parent, <C>: child, (?): don't-care
46     ///
47     ///       DETACHED (-1)  -------------------->  EXITED (?)
48     ///                        <C>finish/exd_tsk
49     ///          ^
50     ///          |
51     ///          | <P>detach
52     ///          |
53     ///
54     ///       INIT (0)  ----------------------->  FINISHED (-1)
55     ///                        <C>finish
56     ///          |                                    |
57     ///          | <P>join/slp_tsk                    | <P>join/del_tsk
58     ///          |                                    | <P>detach/del_tsk
59     ///          v                                    v
60     ///
61     ///       JOINING                              JOINED (?)
62     ///     (parent_tid)
63     ///                                            ^
64     ///             \                             /
65     ///              \  <C>finish/wup_tsk        / <P>slp_tsk-complete/ter_tsk
66     ///               \                         /                      & del_tsk
67     ///                \                       /
68     ///                 '--> JOIN_FINALIZE ---'
69     ///                          (-1)
70     ///
71     lifecycle: AtomicUsize,
72 }
73
74 // Safety: The only `!Sync` field, `ThreadInner::start`, is only touched by
75 //         the task represented by `ThreadInner`.
76 unsafe impl Sync for ThreadInner {}
77
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`
85
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>();
88
89 impl Thread {
90     /// # Safety
91     ///
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),
97         });
98
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 };
103
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()) };
108             p();
109
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() };
115
116             // Run TLS destructors now because they are not
117             // called automatically for terminated tasks.
118             unsafe { run_dtors() };
119
120             let old_lifecycle = inner
121                 .lifecycle
122                 .swap(LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE, Ordering::Release);
123
124             match old_lifecycle {
125                 LIFECYCLE_DETACHED => {
126                     // [DETACHED → EXITED]
127                     // No one will ever join, so we'll ask the collector task to
128                     // delete the task.
129
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
134                     // to `acre_tsk`.
135                     // Safety: See above.
136                     let _ = unsafe { Box::from_raw(p_inner) };
137
138                     // Safety: There are no pinned references to the stack
139                     unsafe { terminate_and_delete_current_task() };
140                 }
141                 LIFECYCLE_INIT => {
142                     // [INIT → FINISHED]
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.
149                 }
150                 parent_tid => {
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.
154
155                     // [JOINING → JOIN_FINALIZE]
156                     // Wake up the parent task.
157                     expect_success(
158                         unsafe {
159                             let mut er = abi::wup_tsk(parent_tid as _);
160                             if er == abi::E_QOVR {
161                                 // `E_QOVR` indicates there's already
162                                 // a parking token
163                                 er = abi::E_OK;
164                             }
165                             er
166                         },
167                         &"wup_tsk",
168                     );
169                 }
170             }
171         }
172
173         // Safety: `Box::into_raw` returns a non-null pointer
174         let p_inner = unsafe { NonNull::new_unchecked(Box::into_raw(inner)) };
175
176         let new_task = ItronError::err_if_negative(unsafe {
177             abi::acre_tsk(&abi::T_CTSK {
178                 // Activate this task immediately
179                 tskatr: abi::TA_ACT,
180                 exinf: p_inner.as_ptr().expose_addr() as abi::EXINF,
181                 // The entry point
182                 task: Some(trampoline),
183                 // Inherit the calling task's base priority
184                 itskpri: abi::TPRI_SELF,
185                 stksz: stack,
186                 // Let the kernel allocate the stack,
187                 stk: crate::ptr::null_mut(),
188             })
189         })
190         .map_err(|e| e.as_io_error())?;
191
192         Ok(Self { p_inner, task: new_task })
193     }
194
195     pub fn yield_now() {
196         expect_success(unsafe { abi::rot_rdq(abi::TPRI_SELF) }, &"rot_rdq");
197     }
198
199     pub fn set_name(_name: &CStr) {
200         // nope
201     }
202
203     pub fn sleep(dur: Duration) {
204         for timeout in dur2reltims(dur) {
205             expect_success(unsafe { abi::dly_tsk(timeout) }, &"dly_tsk");
206         }
207     }
208
209     pub fn join(self) {
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);
218
219         let current_task = current_task as usize;
220
221         match inner.lifecycle.swap(current_task, Ordering::Acquire) {
222             LIFECYCLE_INIT => {
223                 // [INIT → JOINING]
224                 // The child task will transition the state to `JOIN_FINALIZE`
225                 // and wake us up.
226                 loop {
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
231                     // `load`.
232                     if inner.lifecycle.load(Ordering::Acquire) == LIFECYCLE_JOIN_FINALIZE {
233                         break;
234                     }
235                 }
236
237                 // [JOIN_FINALIZE → JOINED]
238             }
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`.
244             }
245             _ => unsafe { hint::unreachable_unchecked() },
246         }
247
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) };
254
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()) };
258
259         // Skip the destructor (because it would attempt to detach the thread)
260         crate::mem::forget(self);
261     }
262 }
263
264 impl Drop for Thread {
265     fn drop(&mut self) {
266         // Safety: `ThreadInner` is alive at this point
267         let inner = unsafe { self.p_inner.as_ref() };
268
269         // Detach the thread.
270         match inner.lifecycle.swap(LIFECYCLE_DETACHED_OR_JOINED, Ordering::Acquire) {
271             LIFECYCLE_INIT => {
272                 // [INIT → DETACHED]
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
278                 // to `acre_tsk`.
279             }
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.
286
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) };
293
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()) };
297             }
298             _ => unsafe { hint::unreachable_unchecked() },
299         }
300     }
301 }
302
303 pub mod guard {
304     pub type Guard = !;
305     pub unsafe fn current() -> Option<Guard> {
306         None
307     }
308     pub unsafe fn init() -> Option<Guard> {
309         None
310     }
311 }
312
313 /// Terminate and delete the specified task.
314 ///
315 /// This function will abort if `deleted_task` refers to the calling task.
316 ///
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.
321 ///
322 /// # Safety
323 ///
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
331         abi::E_OBJ => {}
332         er => {
333             expect_success_aborting(er, &"ter_tsk");
334         }
335     }
336
337     // Delete the task
338     // Safety: Upheld by the caller
339     expect_success_aborting(unsafe { abi::del_tsk(deleted_task) }, &"del_tsk");
340 }
341
342 /// Terminate and delete the calling task.
343 ///
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`.)
348 ///
349 /// # Safety
350 ///
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() };
357 }
358
359 pub fn available_parallelism() -> io::Result<crate::num::NonZeroUsize> {
360     super::unsupported()
361 }