]> git.lizzy.rs Git - rust.git/blob - library/std/src/sys/itron/thread.rs
Merge commit 'b52fb5234cd7c11ecfae51897a6f7fa52e8777fc' into clippyup
[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     sync::atomic::{AtomicUsize, Ordering},
15     sys::thread_local_dtor::run_dtors,
16     time::Duration,
17 };
18
19 pub struct Thread {
20     inner: ManuallyDrop<Box<ThreadInner>>,
21
22     /// The ID of the underlying task.
23     task: abi::ID,
24 }
25
26 /// State data shared between a parent thread and child thread. It's dropped on
27 /// a transition to one of the final states.
28 struct ThreadInner {
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()>>>,
32
33     /// A state machine. Each transition is annotated with `[...]` in the
34     /// source code.
35     ///
36     /// ```text
37     ///
38     ///    <P>: parent, <C>: child, (?): don't-care
39     ///
40     ///       DETACHED (-1)  -------------------->  EXITED (?)
41     ///                        <C>finish/exd_tsk
42     ///          ^
43     ///          |
44     ///          | <P>detach
45     ///          |
46     ///
47     ///       INIT (0)  ----------------------->  FINISHED (-1)
48     ///                        <C>finish
49     ///          |                                    |
50     ///          | <P>join/slp_tsk                    | <P>join/del_tsk
51     ///          |                                    | <P>detach/del_tsk
52     ///          v                                    v
53     ///
54     ///       JOINING                              JOINED (?)
55     ///     (parent_tid)
56     ///                                            ^
57     ///             \                             /
58     ///              \  <C>finish/wup_tsk        / <P>slp_tsk-complete/ter_tsk
59     ///               \                         /                      & del_tsk
60     ///                \                       /
61     ///                 '--> JOIN_FINALIZE ---'
62     ///                          (-1)
63     ///
64     lifecycle: AtomicUsize,
65 }
66
67 // Safety: The only `!Sync` field, `ThreadInner::start`, is only touched by
68 //         the task represented by `ThreadInner`.
69 unsafe impl Sync for ThreadInner {}
70
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`
78
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>();
81
82 impl Thread {
83     /// # Safety
84     ///
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),
90         });
91
92         unsafe extern "C" fn trampoline(exinf: isize) {
93             // Safety: `ThreadInner` is alive at this point
94             let inner = unsafe { &*(exinf as *const ThreadInner) };
95
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()) };
100             p();
101
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() };
107
108             // Run TLS destructors now because they are not
109             // called automatically for terminated tasks.
110             unsafe { run_dtors() };
111
112             let old_lifecycle = inner
113                 .lifecycle
114                 .swap(LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE, Ordering::Release);
115
116             match old_lifecycle {
117                 LIFECYCLE_DETACHED => {
118                     // [DETACHED → EXITED]
119                     // No one will ever join, so we'll ask the collector task to
120                     // delete the task.
121
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
126                     // to `acre_tsk`.
127                     // Safety: See above.
128                     let _ = unsafe { Box::from_raw(inner as *const _ as *mut ThreadInner) };
129
130                     // Safety: There are no pinned references to the stack
131                     unsafe { terminate_and_delete_current_task() };
132                 }
133                 LIFECYCLE_INIT => {
134                     // [INIT → FINISHED]
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.
141                 }
142                 parent_tid => {
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.
146
147                     // [JOINING → JOIN_FINALIZE]
148                     // Wake up the parent task.
149                     expect_success(
150                         unsafe {
151                             let mut er = abi::wup_tsk(parent_tid as _);
152                             if er == abi::E_QOVR {
153                                 // `E_QOVR` indicates there's already
154                                 // a parking token
155                                 er = abi::E_OK;
156                             }
157                             er
158                         },
159                         &"wup_tsk",
160                     );
161                 }
162             }
163         }
164
165         let inner_ptr = (&*inner) as *const ThreadInner;
166
167         let new_task = ItronError::err_if_negative(unsafe {
168             abi::acre_tsk(&abi::T_CTSK {
169                 // Activate this task immediately
170                 tskatr: abi::TA_ACT,
171                 exinf: inner_ptr as abi::EXINF,
172                 // The entry point
173                 task: Some(trampoline),
174                 // Inherit the calling task's base priority
175                 itskpri: abi::TPRI_SELF,
176                 stksz: stack,
177                 // Let the kernel allocate the stack,
178                 stk: crate::ptr::null_mut(),
179             })
180         })
181         .map_err(|e| e.as_io_error())?;
182
183         Ok(Self { inner: ManuallyDrop::new(inner), task: new_task })
184     }
185
186     pub fn yield_now() {
187         expect_success(unsafe { abi::rot_rdq(abi::TPRI_SELF) }, &"rot_rdq");
188     }
189
190     pub fn set_name(_name: &CStr) {
191         // nope
192     }
193
194     pub fn sleep(dur: Duration) {
195         for timeout in dur2reltims(dur) {
196             expect_success(unsafe { abi::dly_tsk(timeout) }, &"dly_tsk");
197         }
198     }
199
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);
208
209         let current_task = current_task as usize;
210
211         match inner.lifecycle.swap(current_task, Ordering::Acquire) {
212             LIFECYCLE_INIT => {
213                 // [INIT → JOINING]
214                 // The child task will transition the state to `JOIN_FINALIZE`
215                 // and wake us up.
216                 loop {
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
221                     // `load`.
222                     if inner.lifecycle.load(Ordering::Acquire) == LIFECYCLE_JOIN_FINALIZE {
223                         break;
224                     }
225                 }
226
227                 // [JOIN_FINALIZE → JOINED]
228             }
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`.
234             }
235             _ => unsafe { hint::unreachable_unchecked() },
236         }
237
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) };
244
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) };
248
249         // Skip the destructor (because it would attempt to detach the thread)
250         crate::mem::forget(self);
251     }
252 }
253
254 impl Drop for Thread {
255     fn drop(&mut self) {
256         // Detach the thread.
257         match self.inner.lifecycle.swap(LIFECYCLE_DETACHED_OR_JOINED, Ordering::Acquire) {
258             LIFECYCLE_INIT => {
259                 // [INIT → DETACHED]
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
265                 // to `acre_tsk`.
266             }
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.
273
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) };
280
281                 // Wwe are responsible for dropping `inner`.
282                 // Safety: The contents of `self.inner` will not be accessed
283                 //         hereafter
284                 unsafe { ManuallyDrop::drop(&mut self.inner) };
285             }
286             _ => unsafe { hint::unreachable_unchecked() },
287         }
288     }
289 }
290
291 pub mod guard {
292     pub type Guard = !;
293     pub unsafe fn current() -> Option<Guard> {
294         None
295     }
296     pub unsafe fn init() -> Option<Guard> {
297         None
298     }
299 }
300
301 /// Terminate and delete the specified task.
302 ///
303 /// This function will abort if `deleted_task` refers to the calling task.
304 ///
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.
309 ///
310 /// # Safety
311 ///
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
319         abi::E_OBJ => {}
320         er => {
321             expect_success_aborting(er, &"ter_tsk");
322         }
323     }
324
325     // Delete the task
326     // Safety: Upheld by the caller
327     expect_success_aborting(unsafe { abi::del_tsk(deleted_task) }, &"del_tsk");
328 }
329
330 /// Terminate and delete the calling task.
331 ///
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`.)
336 ///
337 /// # Safety
338 ///
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() };
345 }
346
347 pub fn available_parallelism() -> io::Result<crate::num::NonZeroUsize> {
348     super::unsupported()
349 }