ove/
workqueue.rs

1// Copyright (C) 2026 Kamil Lulko <kamil.lulko@gmail.com>
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4//
5// This file is part of oveRTOS.
6
7//! Work queue and deferred work items for oveRTOS.
8//!
9//! A [`Workqueue`] runs a dedicated thread that processes [`Work`] items in order.
10//! Work items can be submitted immediately or after a delay, and can be cancelled
11//! before they execute.
12
13use crate::bindings;
14use crate::error::{Error, Result};
15
16/// A workqueue that executes deferred work items on a dedicated thread.
17pub struct Workqueue {
18    handle: bindings::ove_workqueue_t,
19}
20
21impl Workqueue {
22    /// Create a workqueue via heap allocation (only in heap mode).
23    #[cfg(not(zero_heap))]
24    pub fn new(name: &[u8], priority: crate::Priority, stack_size: usize) -> Result<Self> {
25        let mut handle: bindings::ove_workqueue_t = core::ptr::null_mut();
26        let rc = unsafe {
27            bindings::ove_workqueue_create(
28                &mut handle,
29                name.as_ptr() as *const _,
30                priority as u32,
31                stack_size,
32            )
33        };
34        Error::from_code(rc)?;
35        Ok(Self { handle })
36    }
37
38    /// Create from caller-provided static storage and stack.
39    ///
40    /// # Safety
41    /// - `storage` must outlive the `Workqueue` and not be shared.
42    /// - `stack` must point to at least `stack_size` bytes and outlive
43    ///   the `Workqueue`.
44    #[cfg(zero_heap)]
45    pub unsafe fn from_static(
46        storage: *mut bindings::ove_workqueue_storage_t,
47        name: &[u8],
48        priority: crate::Priority,
49        stack_size: usize,
50        stack: *mut core::ffi::c_void,
51    ) -> Result<Self> {
52        let mut handle: bindings::ove_workqueue_t = core::ptr::null_mut();
53        let rc = unsafe {
54            bindings::ove_workqueue_init(
55                &mut handle,
56                storage,
57                name.as_ptr() as *const _,
58                priority as u32,
59                stack_size,
60                stack,
61            )
62        };
63        Error::from_code(rc)?;
64        Ok(Self { handle })
65    }
66
67    /// Return the raw handle for use with `Work::submit`.
68    pub fn handle(&self) -> bindings::ove_workqueue_t {
69        self.handle
70    }
71}
72
73impl Drop for Workqueue {
74    fn drop(&mut self) {
75        if self.handle.is_null() { return; }
76        #[cfg(not(zero_heap))]
77        unsafe { bindings::ove_workqueue_destroy(self.handle) }
78        #[cfg(zero_heap)]
79        unsafe { bindings::ove_workqueue_deinit(self.handle) }
80    }
81}
82
83// SAFETY: Workqueue wraps a ove_workqueue_t handle. All RTOS operations on the
84// handle are internally thread-safe. Create/destroy are single-threaded (lifecycle).
85unsafe impl Send for Workqueue {}
86unsafe impl Sync for Workqueue {}
87
88/// A work item that can be submitted to a [`Workqueue`].
89pub struct Work {
90    handle: bindings::ove_work_t,
91}
92
93impl Work {
94    /// Create a work item via heap allocation (only in heap mode).
95    ///
96    /// The handler receives the raw `ove_work_t` handle (the C API does
97    /// not provide a user_data parameter for work handlers).
98    ///
99    /// # Errors
100    /// Returns [`Error::NoMemory`] if heap allocation fails.
101    #[cfg(not(zero_heap))]
102    pub fn new(handler: bindings::ove_work_fn) -> Result<Self> {
103        let mut handle: bindings::ove_work_t = core::ptr::null_mut();
104        let rc = unsafe { bindings::ove_work_init(&mut handle, handler) };
105        Error::from_code(rc)?;
106        Ok(Self { handle })
107    }
108
109    /// Create from caller-provided static storage.
110    ///
111    /// # Safety
112    /// Caller must ensure `storage` outlives the `Work` item.
113    #[cfg(zero_heap)]
114    pub unsafe fn from_static(
115        storage: *mut bindings::ove_work_storage_t,
116        handler: bindings::ove_work_fn,
117    ) -> Result<Self> {
118        let mut handle: bindings::ove_work_t = core::ptr::null_mut();
119        let rc = unsafe { bindings::ove_work_init_static(&mut handle, storage, handler) };
120        Error::from_code(rc)?;
121        Ok(Self { handle })
122    }
123
124    /// Submit this work item to `wq` for immediate execution.
125    ///
126    /// # Errors
127    /// Returns an error if the workqueue is shutting down or the item is already pending.
128    pub fn submit(&self, wq: &Workqueue) -> Result<()> {
129        let rc = unsafe { bindings::ove_work_submit(wq.handle(), self.handle) };
130        Error::from_code(rc)
131    }
132
133    /// Submit this work item to `wq` for execution after `delay_ms` milliseconds.
134    ///
135    /// # Errors
136    /// Returns an error if the workqueue is shutting down or the item is already pending.
137    pub fn submit_delayed(&self, wq: &Workqueue, delay_ms: u32) -> Result<()> {
138        let rc =
139            unsafe { bindings::ove_work_submit_delayed(wq.handle(), self.handle, delay_ms) };
140        Error::from_code(rc)
141    }
142
143    /// Cancel this work item if it is pending or delayed.
144    ///
145    /// Has no effect if the item is not currently queued.
146    ///
147    /// # Errors
148    /// Returns an error if the underlying RTOS call fails.
149    pub fn cancel(&self) -> Result<()> {
150        let rc = unsafe { bindings::ove_work_cancel(self.handle) };
151        Error::from_code(rc)
152    }
153}
154
155impl Drop for Work {
156    fn drop(&mut self) {
157        if self.handle.is_null() { return; }
158        #[cfg(not(zero_heap))]
159        unsafe { bindings::ove_work_free(self.handle) }
160        #[cfg(zero_heap)]
161        { self.handle = core::ptr::null_mut(); }
162    }
163}
164
165unsafe impl Send for Work {}
166unsafe impl Sync for Work {}