1use core::fmt;
14
15use crate::bindings;
16use crate::error::{Error, Result};
17use crate::priority::Priority;
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub enum ThreadState {
22 Running,
24 Ready,
26 Blocked,
28 Suspended,
30 Terminated,
32 Unknown,
34}
35
36#[derive(Debug, Clone, Copy)]
38pub struct ThreadStats {
39 pub runtime_us: u64,
41 pub cpu_percent_x100: u32,
43}
44
45pub struct Thread {
50 handle: bindings::ove_thread_t,
51 owned: bool,
52}
53
54impl Thread {
55 pub fn sleep_ms(ms: u32) {
57 unsafe { bindings::ove_thread_sleep_ms(ms) }
58 }
59
60 pub fn yield_now() {
62 unsafe { bindings::ove_thread_yield() }
63 }
64
65 pub fn current() -> Self {
70 let handle = unsafe { bindings::ove_thread_get_self() };
71 Self { handle, owned: false }
72 }
73
74 #[cfg(not(zero_heap))]
83 pub fn create(
84 name: &[u8],
85 entry: unsafe extern "C" fn(*mut core::ffi::c_void),
86 priority: Priority,
87 stack_size: usize,
88 ) -> Result<Self> {
89 let desc = bindings::ove_thread_desc {
90 name: name.as_ptr() as *const _,
91 entry: Some(entry),
92 arg: core::ptr::null_mut(),
93 priority: priority as bindings::ove_prio_t,
94 stack_size,
95 stack: core::ptr::null_mut(),
96 };
97 let mut handle: bindings::ove_thread_t = core::ptr::null_mut();
98 let rc = unsafe { bindings::ove_thread_create_(&mut handle, &desc) };
99 Error::from_code(rc)?;
100 Ok(Self { handle, owned: true })
101 }
102
103 #[cfg(not(zero_heap))]
112 pub fn spawn(
113 name: &[u8],
114 entry: fn(),
115 priority: Priority,
116 stack_size: usize,
117 ) -> Result<Self> {
118 unsafe extern "C" fn trampoline(arg: *mut core::ffi::c_void) {
119 let entry: fn() = unsafe { core::mem::transmute(arg) };
120 entry();
121 }
122
123 let desc = bindings::ove_thread_desc {
124 name: name.as_ptr() as *const _,
125 entry: Some(trampoline),
126 arg: entry as *mut core::ffi::c_void,
127 priority: priority as bindings::ove_prio_t,
128 stack_size,
129 stack: core::ptr::null_mut(),
130 };
131 let mut handle: bindings::ove_thread_t = core::ptr::null_mut();
132 let rc = unsafe { bindings::ove_thread_create_(&mut handle, &desc) };
133 Error::from_code(rc)?;
134 Ok(Self { handle, owned: true })
135 }
136
137 #[cfg(zero_heap)]
145 pub unsafe fn from_static(
146 storage: *mut bindings::ove_thread_storage_t,
147 desc: &bindings::ove_thread_desc,
148 ) -> Result<Self> {
149 let mut handle: bindings::ove_thread_t = core::ptr::null_mut();
150 let rc = unsafe { bindings::ove_thread_init(&mut handle, storage, desc) };
151 Error::from_code(rc)?;
152 Ok(Self { handle, owned: true })
153 }
154
155 #[cfg(zero_heap)]
164 pub unsafe fn spawn_static(
165 storage: *mut bindings::ove_thread_storage_t,
166 stack: *mut core::ffi::c_void,
167 name: &[u8],
168 entry: fn(),
169 priority: Priority,
170 stack_size: usize,
171 ) -> Result<Self> {
172 unsafe extern "C" fn trampoline(arg: *mut core::ffi::c_void) {
173 let entry: fn() = unsafe { core::mem::transmute(arg) };
174 entry();
175 }
176
177 let desc = bindings::ove_thread_desc {
178 name: name.as_ptr() as *const _,
179 entry: Some(trampoline),
180 arg: entry as *mut core::ffi::c_void,
181 priority: priority as bindings::ove_prio_t,
182 stack_size,
183 stack,
184 };
185 let mut handle: bindings::ove_thread_t = core::ptr::null_mut();
186 let rc = unsafe { bindings::ove_thread_init(&mut handle, storage, &desc) };
187 Error::from_code(rc)?;
188 Ok(Self { handle, owned: true })
189 }
190
191 pub fn suspend(&self) {
193 unsafe { bindings::ove_thread_suspend(self.handle) }
194 }
195
196 pub fn resume(&self) {
198 unsafe { bindings::ove_thread_resume(self.handle) }
199 }
200
201 pub fn set_priority(&self, prio: Priority) {
203 unsafe { bindings::ove_thread_set_priority(self.handle, prio as bindings::ove_prio_t) }
204 }
205
206 pub fn get_stack_usage(&self) -> usize {
208 unsafe { bindings::ove_thread_get_stack_usage(self.handle) }
209 }
210
211 pub fn get_state(&self) -> ThreadState {
213 let state = unsafe { bindings::ove_thread_get_state(self.handle) };
214 match state {
215 bindings::OVE_THREAD_STATE_RUNNING => ThreadState::Running,
216 bindings::OVE_THREAD_STATE_READY => ThreadState::Ready,
217 bindings::OVE_THREAD_STATE_BLOCKED => ThreadState::Blocked,
218 bindings::OVE_THREAD_STATE_SUSPENDED => {
219 ThreadState::Suspended
220 }
221 bindings::OVE_THREAD_STATE_TERMINATED => {
222 ThreadState::Terminated
223 }
224 _ => ThreadState::Unknown,
225 }
226 }
227
228 pub fn get_runtime_stats(&self) -> Result<ThreadStats> {
234 let mut stats = bindings::ove_thread_stats {
235 runtime_us: 0,
236 cpu_percent_x100: 0,
237 };
238 let rc =
239 unsafe { bindings::ove_thread_get_runtime_stats(self.handle, &mut stats) };
240 Error::from_code(rc)?;
241 Ok(ThreadStats {
242 runtime_us: stats.runtime_us,
243 cpu_percent_x100: stats.cpu_percent_x100,
244 })
245 }
246}
247
248impl fmt::Debug for Thread {
249 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
250 f.debug_struct("Thread")
251 .field("handle", &format_args!("{:p}", self.handle))
252 .field("owned", &self.owned)
253 .finish()
254 }
255}
256
257#[derive(Debug, Clone, Copy)]
263pub struct MemStats {
264 pub total: usize,
266 pub free: usize,
268 pub used: usize,
270 pub peak_used: usize,
272}
273
274pub fn get_mem_stats() -> Result<MemStats> {
279 let mut raw: bindings::ove_mem_stats = unsafe { core::mem::zeroed() };
280 let rc = unsafe { bindings::ove_sys_get_mem_stats(&mut raw) };
281 Error::from_code(rc)?;
282 Ok(MemStats {
283 total: raw.total,
284 free: raw.free,
285 used: raw.used,
286 peak_used: raw.peak_used,
287 })
288}
289
290#[derive(Debug, Clone, Copy)]
296pub struct ThreadInfo {
297 pub name: &'static [u8],
299 pub state: bindings::ove_thread_state_t,
301 pub priority: i32,
303 pub stack_used: usize,
305}
306
307pub fn thread_list(buf: &mut [ThreadInfo]) -> Result<&[ThreadInfo]> {
315 const MAX_THREADS: usize = 32;
316 let count = buf.len().min(MAX_THREADS);
317 let mut raw: [bindings::ove_thread_info; MAX_THREADS] = unsafe { core::mem::zeroed() };
318 let mut actual: usize = 0;
319 let rc = unsafe { bindings::ove_thread_list(raw.as_mut_ptr(), count, &mut actual) };
320 Error::from_code(rc)?;
321
322 let actual = actual.min(count);
323 for i in 0..actual {
324 let name = if raw[i].name.is_null() {
325 &[]
326 } else {
327 unsafe {
328 let p = raw[i].name as *const u8;
329 let mut len = 0;
330 while *p.add(len) != 0 {
331 len += 1;
332 }
333 core::slice::from_raw_parts(p, len)
334 }
335 };
336 buf[i] = ThreadInfo {
337 name,
338 state: raw[i].state,
339 priority: raw[i].priority,
340 stack_used: raw[i].stack_used,
341 };
342 }
343 Ok(&buf[..actual])
344}
345
346impl Drop for Thread {
347 fn drop(&mut self) {
348 if self.owned && !self.handle.is_null() {
349 #[cfg(not(zero_heap))]
350 unsafe { bindings::ove_thread_destroy(self.handle) };
351 #[cfg(zero_heap)]
352 unsafe { bindings::ove_thread_deinit(self.handle) };
353 }
354 }
355}