zephyr/sys/sync/mutex.rs
1// Copyright (c) 2024 Linaro LTD
2// SPDX-License-Identifier: Apache-2.0
3
4//! Zephyr `k_mutex` wrapper.
5//!
6//! This module implements a thing wrapper around the `k_mutex` type in Zephyr. It works with the
7//! kernel [`object`] system, to allow the mutexes to be defined statically.
8//!
9//! [`object`]: crate::object
10
11use crate::object::{ObjectInit, StaticKernelObject, ZephyrObject};
12use crate::sys::K_FOREVER;
13use crate::{
14 error::{to_result_void, Result},
15 raw::{
16 k_condvar, k_condvar_broadcast, k_condvar_init, k_condvar_signal, k_condvar_wait, k_mutex,
17 k_mutex_init, k_mutex_lock, k_mutex_unlock,
18 },
19 time::Timeout,
20};
21use core::fmt;
22
23/// A Zephyr `k_mutux` usable from safe Rust code.
24///
25/// This merely wraps a pointer to the kernel object. It implements clone, send and sync as it is
26/// safe to have multiple instances of these, as well as use them across multiple threads.
27///
28/// Note that these are Safe in the sense that memory safety is guaranteed. Attempts to
29/// recursively lock, or incorrect nesting can easily result in deadlock.
30///
31/// Safety: Typically, the Mutex type in Rust does not implement Clone, and must be shared between
32/// threads using Arc. However, these sys Mutexes are wrappers around static kernel objects, and
33/// Drop doesn't make sense for them. In addition, Arc requires alloc, and one possible place to
34/// make use of the sys Mutex is to be able to do so in an environment without alloc.
35///
36/// This mutex type of only of limited use to application programs. It can be used as a simple
37/// binary semaphore, although it has strict semantics, requiring the release to be called by the
38/// same thread that called lock. It can be used to protect data that Rust itself is either not
39/// managing, or is managing in an unsafe way.
40///
41/// For a Mutex type that is useful in a Rust type of manner, please see the regular [`sync::Mutex`]
42/// type.
43///
44/// [`sync::Mutex`]: http://example.com/TODO
45pub struct Mutex {
46 /// The raw Zephyr mutex.
47 item: ZephyrObject<k_mutex>,
48}
49
50impl Mutex {
51 /// Create a new Mutex in an unlocked state.
52 ///
53 /// Create a new dynamically allocated Mutex. The Mutex can only be used from system threads.
54 pub const fn new() -> Mutex {
55 Mutex {
56 item: <ZephyrObject<k_mutex>>::new_raw(),
57 }
58 }
59
60 /// Lock a Zephyr Mutex.
61 ///
62 /// Will wait for the lock, returning status, with `Ok(())` indicating the lock has been
63 /// acquired, and an error indicating a timeout (Zephyr returns different errors depending on
64 /// the reason).
65 pub fn lock<T>(&self, timeout: T) -> Result<()>
66 where
67 T: Into<Timeout>,
68 {
69 let timeout: Timeout = timeout.into();
70 to_result_void(unsafe { k_mutex_lock(self.item.get(), timeout.0) })
71 }
72
73 /// Unlock a Zephyr Mutex.
74 ///
75 /// The mutex must already be locked by the calling thread. Mutexes may not be unlocked in
76 /// ISRs.
77 pub fn unlock(&self) -> Result<()> {
78 to_result_void(unsafe { k_mutex_unlock(self.item.get()) })
79 }
80}
81
82impl ObjectInit<k_mutex> for ZephyrObject<k_mutex> {
83 fn init(item: *mut k_mutex) {
84 // SAFETY: ZephyrObject handles initialization and move prevention.
85 unsafe {
86 k_mutex_init(item);
87 }
88 }
89}
90
91/// A static Zephyr `k_mutex`
92///
93/// This is intended to be used from within the `kobj_define!` macro. It declares a static
94/// `k_mutex` that will be properly registered with the Zephyr object system. Call [`init_once`] to
95/// get the [`Mutex`] that it represents.
96///
97/// [`init_once`]: StaticMutex::init_once
98pub type StaticMutex = StaticKernelObject<k_mutex>;
99
100unsafe impl Sync for Mutex {}
101unsafe impl Send for Mutex {}
102
103// Sync and Send are meaningful, as the underlying Zephyr API can use these values from any thread.
104// Care must be taken to use these in a safe manner.
105unsafe impl Sync for StaticMutex {}
106unsafe impl Send for StaticMutex {}
107
108impl fmt::Debug for Mutex {
109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110 // SAFETY: Address is just gotten to print for diagnostics.
111 write!(f, "sys::Mutex {:?}", unsafe { self.item.get() })
112 }
113}
114
115/// A Condition Variable
116///
117/// Lightweight wrappers for Zephyr's `k_condvar`.
118pub struct Condvar {
119 item: ZephyrObject<k_condvar>,
120}
121
122#[doc(hidden)]
123pub type StaticCondvar = StaticKernelObject<k_condvar>;
124
125unsafe impl Sync for StaticKernelObject<k_condvar> {}
126
127unsafe impl Sync for Condvar {}
128unsafe impl Send for Condvar {}
129
130impl Condvar {
131 /// Create a new Condvar.
132 ///
133 /// Create a new dynamically allocated Condvar. The Condvar can only be used from system threads.
134 pub const fn new() -> Condvar {
135 Condvar {
136 item: <ZephyrObject<k_condvar>>::new_raw(),
137 }
138 }
139
140 /// Wait for someone else using this mutex/condvar pair to notify.
141 ///
142 /// Note that this requires the lock to be held by use, but as this is a low-level binding to
143 /// Zephyr's interfaces, this is not enforced. See [`sync::Condvar`] for a safer and easier to
144 /// use interface.
145 ///
146 /// [`sync::Condvar`]: http://www.example.com/TODO
147 // /// [`sync::Condvar`]: crate::sync::Condvar
148 pub fn wait(&self, lock: &Mutex) {
149 unsafe {
150 k_condvar_wait(self.item.get(), lock.item.get(), K_FOREVER);
151 }
152 }
153
154 // TODO: timeout.
155
156 /// Wake a single thread waiting on this condition variable.
157 pub fn notify_one(&self) {
158 unsafe {
159 k_condvar_signal(self.item.get());
160 }
161 }
162
163 /// Wake all threads waiting on this condition variable.
164 pub fn notify_all(&self) {
165 unsafe {
166 k_condvar_broadcast(self.item.get());
167 }
168 }
169}
170
171impl ObjectInit<k_condvar> for ZephyrObject<k_condvar> {
172 fn init(item: *mut k_condvar) {
173 // SAFETY: ZephyrObject handles initialization and move prevention.
174 unsafe {
175 k_condvar_init(item);
176 }
177 }
178}
179
180impl fmt::Debug for Condvar {
181 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182 // SAFETY: Just getting the address to print.
183 write!(f, "sys::Condvar {:?}", unsafe { self.item.get() })
184 }
185}