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}