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};
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
78impl ObjectInit<k_queue> for ZephyrObject<k_queue> {
79    fn init(item: *mut k_queue) {
80        // SAFETY: ZephyrObject handles initialization and move prevention.
81        unsafe {
82            k_queue_init(item);
83        }
84    }
85}
86
87impl fmt::Debug for Queue {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        // SAFETY: Just getting the address to print.
90        write!(f, "sys::Queue {:?}", unsafe { self.0.get() })
91    }
92}