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