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}