• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Google Inc. All rights reserved
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files
6  * (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 
24 use alloc::boxed::Box;
25 use core::ffi::c_int;
26 use core::ffi::c_void;
27 use core::ffi::CStr;
28 use core::fmt;
29 use core::fmt::Display;
30 use core::fmt::Formatter;
31 use core::ops::Add;
32 use core::ops::Sub;
33 use core::ptr::NonNull;
34 use core::time::Duration;
35 
36 use crate::Error;
37 use crate::INFINITE_TIME;
38 
39 use crate::sys::lk_time_ns_t;
40 use crate::sys::lk_time_t;
41 use crate::sys::thread_create;
42 use crate::sys::thread_join;
43 use crate::sys::thread_resume;
44 use crate::sys::thread_sleep_ns;
45 use crate::sys::thread_t;
46 use crate::sys::DEFAULT_PRIORITY;
47 use crate::sys::DPC_PRIORITY;
48 use crate::sys::HIGHEST_PRIORITY;
49 use crate::sys::HIGH_PRIORITY;
50 use crate::sys::IDLE_PRIORITY;
51 use crate::sys::LOWEST_PRIORITY;
52 use crate::sys::LOW_PRIORITY;
53 use crate::sys::NUM_PRIORITIES;
54 
55 use crate::sys::DEFAULT_STACK_SIZE;
56 
sleep(dur: Duration)57 pub fn sleep(dur: Duration) {
58     let dur_ns: lk_time_ns_t = dur.as_nanos().try_into().expect("could not convert duration to ns");
59     // Safety: trivially safe
60     unsafe { thread_sleep_ns(dur_ns) };
61 }
62 
63 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
64 pub struct Priority(c_int);
65 
66 impl Priority {
67     pub const NUM: usize = NUM_PRIORITIES as _;
68 
69     pub const LOWEST: Self = Self(LOWEST_PRIORITY as _);
70     pub const HIGHEST: Self = Self(HIGHEST_PRIORITY as _);
71     pub const DPC: Self = Self(DPC_PRIORITY as _);
72     pub const IDLE: Self = Self(IDLE_PRIORITY as _);
73     pub const LOW: Self = Self(LOW_PRIORITY as _);
74     pub const DEFAULT: Self = Self(DEFAULT_PRIORITY as _);
75     pub const HIGH: Self = Self(HIGH_PRIORITY as _);
76 }
77 
78 impl Default for Priority {
default() -> Self79     fn default() -> Self {
80         Self::DEFAULT
81     }
82 }
83 
84 #[derive(Debug)]
85 pub enum PriorityError {
86     TooLow(c_int),
87     TooHigh(c_int),
88 }
89 
90 impl Display for PriorityError {
fmt(&self, f: &mut Formatter) -> fmt::Result91     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
92         match self {
93             PriorityError::TooLow(val) => write!(f, "{val} < {}", Priority::LOWEST.0),
94             PriorityError::TooHigh(val) => write!(f, "{val} > {}", Priority::HIGHEST.0),
95         }
96     }
97 }
98 
99 impl TryFrom<c_int> for Priority {
100     type Error = PriorityError;
101 
try_from(value: c_int) -> Result<Self, Self::Error>102     fn try_from(value: c_int) -> Result<Self, Self::Error> {
103         if value < Priority::LOWEST.0 {
104             Err(PriorityError::TooLow(value))
105         } else if value > Priority::HIGHEST.0 {
106             Err(PriorityError::TooHigh(value))
107         } else {
108             Ok(Priority(value))
109         }
110     }
111 }
112 
113 impl Add<c_int> for Priority {
114     type Output = Self;
115 
add(self, other: c_int) -> Self116     fn add(self, other: c_int) -> Self {
117         match self.0.checked_add(other).map(Self::try_from) {
118             None => panic!("priority overflow"),
119             Some(Err(reason)) => panic!("priority out of range: {reason}"),
120             Some(Ok(priority)) => priority,
121         }
122     }
123 }
124 
125 impl Sub<c_int> for Priority {
126     type Output = Self;
127 
sub(self, other: c_int) -> Self128     fn sub(self, other: c_int) -> Self {
129         match self.0.checked_sub(other).map(Self::try_from) {
130             None => panic!("priority overflow"),
131             Some(Err(reason)) => panic!("priority out of range: {reason}"),
132             Some(Ok(priority)) => priority,
133         }
134     }
135 }
136 
137 pub struct JoinHandle {
138     thread: NonNull<thread_t>,
139 }
140 
141 impl JoinHandle {
142     /// Waits a given amount of time for the associated thread to finish. Waits indefinitely if
143     /// timeout is None.
join(self, timeout: Option<Duration>) -> Result<c_int, Error>144     pub fn join(self, timeout: Option<Duration>) -> Result<c_int, Error> {
145         let timeout_ms: lk_time_t = timeout.map_or(INFINITE_TIME, |t| {
146             t.as_millis().try_into().expect("could not convert timeout to milliseconds")
147         });
148         let mut rc = 0;
149         // SAFETY: The thread pointer came from a call to thread_create and must be non-null. The
150         // retcode pointer points to the stack of the calling thread which will live as long as
151         // needed since thread_join blocks.
152         let status = unsafe { thread_join(self.thread.as_ptr(), &raw mut rc, timeout_ms) };
153         Error::from_lk(status)?;
154         Ok(rc)
155     }
156 }
157 
158 #[derive(Debug)]
159 pub struct Builder<'a> {
160     pub name: Option<&'a CStr>,
161     pub priority: Priority,
162     pub stack_size: usize,
163 }
164 
165 impl Default for Builder<'_> {
default() -> Self166     fn default() -> Self {
167         Self::new()
168     }
169 }
170 
171 impl<'a> Builder<'a> {
new() -> Self172     pub const fn new() -> Self {
173         Self { name: None, priority: Priority::DEFAULT, stack_size: DEFAULT_STACK_SIZE as _ }
174     }
175 
name(mut self, name: &'a CStr) -> Self176     pub fn name(mut self, name: &'a CStr) -> Self {
177         self.name = Some(name);
178         self
179     }
180 
priority(mut self, priority: Priority) -> Self181     pub fn priority(mut self, priority: Priority) -> Self {
182         self.priority = priority;
183         self
184     }
185 
stack_size(mut self, stack_size: usize) -> Self186     pub fn stack_size(mut self, stack_size: usize) -> Self {
187         self.stack_size = stack_size;
188         self
189     }
190 
spawn<F>(self, f: F) -> Result<JoinHandle, i32> where F: FnOnce() -> c_int + Send + 'static,191     pub fn spawn<F>(self, f: F) -> Result<JoinHandle, i32>
192     where
193         F: FnOnce() -> c_int + Send + 'static,
194     {
195         let name = self.name.unwrap_or(c"thread");
196         // We need a pointer to f that lasts until `thread_entry_wrapper`
197         // gets called. `thread_resume` does not wait for the new
198         // thread to run. Thus, passing the address of a local
199         // wouldn't live long enough so we heap allocate instead.
200         let f = Box::new(f);
201 
202         extern "C" fn thread_entry_wrapper<F>(arg: *mut c_void) -> c_int
203         where
204             F: FnOnce() -> c_int + Send + 'static,
205         {
206             // SAFETY:
207             // We passed in a `Box<F>`.
208             // `thread_entry_wrapper` is called exactly once per thread.
209             let f = unsafe { Box::<F>::from_raw(arg as _) };
210             f()
211         }
212 
213         // SAFETY:
214         // `name` outlives the call to `thread_create` during which the
215         // string is copied into the newly created thread structure.
216         //
217         // `arg`: The lifetime of `Box<F>` lasts until the end of the
218         // call to `thread_entry_wrapper`. The trusty kernel will pass `arg`
219         // to `thread_entry_wrapper` exactly once per thread.
220         let thread = unsafe {
221             thread_create(
222                 name.as_ptr(),
223                 Some(thread_entry_wrapper::<F>),
224                 Box::<F>::into_raw(f) as *mut c_void,
225                 self.priority.0,
226                 self.stack_size,
227             )
228         };
229         let thread = NonNull::new(thread).ok_or::<i32>(Error::ERR_GENERIC.into())?;
230         // SAFETY: `thread` is non-null, so `thread_create` initialized it properly.
231         let status = unsafe { thread_resume(thread.as_ptr()) };
232         if status == Error::NO_ERROR.into() {
233             Ok(JoinHandle { thread })
234         } else {
235             Err(status)
236         }
237     }
238 }
239 
spawn<F>(f: F) -> Result<JoinHandle, i32> where F: FnOnce() -> c_int + Send + 'static,240 pub fn spawn<F>(f: F) -> Result<JoinHandle, i32>
241 where
242     F: FnOnce() -> c_int + Send + 'static,
243 {
244     Builder::new().spawn(f)
245 }
246