Skip to main content

zephyr/sys/
queue.rs

1//! Lightweight wrapper around Zephyr's `k_queue`.
2//!
3//! The underlying operations on the `k_queue` are all unsafe, as the model does not match the
4//! borrowing model that Rust expects.  This module is mainly intended to be used by the
5//! implementation of `zephyr::sys::channel`, which can be used without needing unsafe.
6
7use core::ffi::c_void;
8use core::fmt;
9
10use zephyr_sys::{k_queue, k_queue_append, k_queue_get, k_queue_init, k_queue_remove};
11
12use crate::object::{ObjectInit, ZephyrObject};
13use crate::time::Timeout;
14
15/// A wrapper around a Zephyr `k_queue` object.
16pub struct Queue(pub(crate) ZephyrObject<k_queue>);
17
18unsafe impl Sync for Queue {}
19unsafe impl Send for Queue {}
20
21impl Queue {
22    /// Create a new Queue, dynamically allocated.
23    ///
24    /// This Queue can only be used from system threads.
25    ///
26    /// **Note**: When a Queue is dropped, any messages that have been added to the queue will be
27    /// leaked.
28    pub const fn new() -> Queue {
29        Queue(<ZephyrObject<k_queue>>::new_raw())
30    }
31
32    /// Append an element to the end of a queue.
33    ///
34    /// This adds an element to the given [`Queue`].  Zephyr requires the
35    /// first word of this message to be available for the OS to enqueue
36    /// the message.  See [`Message`] for details on how this can be used
37    /// safely.
38    ///
39    /// [`Message`]: crate::sync::channel::Message
40    ///
41    /// # Safety
42    ///
43    /// Zephyr has specific requirements on the memory given in data, which can be summarized as:
44    /// - The memory must remain valid until after the data is returned, via recv.
45    /// - The first `usize` in the pointed data will be mutated by Zephyr to manage structures.
46    /// - This first field must not be modified by any code while the message is enqueued.
47    ///
48    /// These are easiest to satisfy by ensuring the message is Boxed, and owned by the queue
49    /// system.
50    pub unsafe fn send(&self, data: *mut c_void) {
51        k_queue_append(self.0.get(), data)
52    }
53
54    /// Get an element from a queue.
55    ///
56    /// This routine removes the first data item from the [`Queue`].
57    /// The timeout value can be [`Forever`] to block until there is a message, [`NoWait`] to check
58    /// and immediately return if there is no message, or a [`Duration`] to indicate a specific
59    /// timeout.
60    ///
61    /// [`Forever`]: crate::time::Forever
62    /// [`NoWait`]: crate::time::NoWait
63    /// [`Duration`]: crate::time::Duration
64    ///
65    /// # Safety
66    ///
67    /// Once an item is received from a queue, ownership is returned to the caller, and Zephyr no
68    /// longer depends on it not being freed, or the first `usize` field being for its use.
69    pub unsafe fn recv<T>(&self, timeout: T) -> *mut c_void
70    where
71        T: Into<Timeout>,
72    {
73        let timeout: Timeout = timeout.into();
74        k_queue_get(self.0.get(), timeout.0)
75    }
76
77    /// Remove a specific element from the queue, if it is still present.
78    ///
79    /// Returns `true` if `data` was found in the queue and removed, `false` otherwise (for
80    /// example, it was never queued, or has already been received by another thread).
81    ///
82    /// # Safety
83    ///
84    /// `data` must be a pointer previously passed to [`send`](Self::send) on this queue (or null).
85    /// If it is removed, ownership returns to the caller, exactly as with [`recv`](Self::recv).
86    pub unsafe fn remove(&self, data: *mut c_void) -> bool {
87        k_queue_remove(self.0.get(), data)
88    }
89}
90
91impl ObjectInit<k_queue> for ZephyrObject<k_queue> {
92    fn init(item: *mut k_queue) {
93        // SAFETY: ZephyrObject handles initialization and move prevention.
94        unsafe {
95            k_queue_init(item);
96        }
97    }
98}
99
100impl fmt::Debug for Queue {
101    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102        // SAFETY: Just getting the address to print.
103        write!(f, "sys::Queue {:?}", unsafe { self.0.get() })
104    }
105}