zephyr/sys/sync/semaphore.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
// Copyright (c) 2024 Linaro LTD
// SPDX-License-Identifier: Apache-2.0
//! Zephyr Semaphore support
//!
//! This is a thin wrapper around Zephyr's `k_sem`. This is one of the few of the `sys` primitives
//! in Zephyr that is actually perfectly usable on its own, without needing additional wrappers.
//!
//! Zephyr implements counting semaphores, with both an upper and lower bound on the count. Note
//! that calling 'give' on a semaphore that is at the maximum count will discard the 'give'
//! operation, which in situation where counting is actually desired, will result in the count being
//! incorrect.
use core::ffi::c_uint;
use core::fmt;
#[cfg(CONFIG_RUST_ALLOC)]
use core::mem;
use crate::{
error::{to_result_void, Result},
object::{Fixed, StaticKernelObject, Wrapped},
raw::{
k_sem, k_sem_count_get, k_sem_give, k_sem_init, k_sem_reset, k_sem_take
},
time::Timeout,
};
pub use crate::raw::K_SEM_MAX_LIMIT;
/// A zephyr `k_sem` usable from safe Rust code.
pub struct Semaphore {
/// The raw Zephyr `k_sem`.
item: Fixed<k_sem>,
}
/// By nature, Semaphores are both Sync and Send. Safety is handled by the underlying Zephyr
/// implementation (which is why Clone is also implemented).
unsafe impl Sync for Semaphore {}
unsafe impl Send for Semaphore {}
impl Semaphore {
/// Create a new semaphore.
///
/// Create a new dynamically allocated Semaphore. This semaphore can only be used from system
/// threads. The arguments are as described in [the
/// docs](https://docs.zephyrproject.org/latest/kernel/services/synchronization/semaphores.html).
#[cfg(CONFIG_RUST_ALLOC)]
pub fn new(initial_count: c_uint, limit: c_uint) -> Result<Semaphore> {
let item: Fixed<k_sem> = Fixed::new(unsafe { mem::zeroed() });
unsafe {
to_result_void(k_sem_init(item.get(), initial_count, limit))?;
}
Ok(Semaphore { item })
}
/// Take a semaphore.
///
/// Can be called from ISR if called with [`NoWait`].
///
/// [`NoWait`]: crate::time::NoWait
pub fn take<T>(&self, timeout: T) -> Result<()>
where T: Into<Timeout>,
{
let timeout: Timeout = timeout.into();
let ret = unsafe {
k_sem_take(self.item.get(), timeout.0)
};
to_result_void(ret)
}
/// Give a semaphore.
///
/// This routine gives to the semaphore, unless the semaphore is already at its maximum
/// permitted count.
pub fn give(&self) {
unsafe {
k_sem_give(self.item.get())
}
}
/// Resets a semaphor's count to zero.
///
/// This resets the count to zero. Any outstanding [`take`] calls will be aborted with
/// `Error(EAGAIN)`.
///
/// [`take`]: Self::take
pub fn reset(&mut self) {
unsafe {
k_sem_reset(self.item.get())
}
}
/// Get a semaphore's count.
///
/// Returns the current count.
pub fn count_get(&mut self) -> usize {
unsafe {
k_sem_count_get(self.item.get()) as usize
}
}
}
/// A static Zephyr `k_sem`.
///
/// This is intended to be used from within the `kobj_define!` macro. It declares a static ksem
/// that will be properly registered with the Zephyr kernel object system. Call [`init_once`] to
/// get the [`Semaphore`] that is represents.
///
/// [`init_once`]: StaticKernelObject::init_once
pub type StaticSemaphore = StaticKernelObject<k_sem>;
unsafe impl Sync for StaticSemaphore {}
impl Wrapped for StaticKernelObject<k_sem> {
type T = Semaphore;
/// The initializer for Semaphores is the initial count, and the count limit (which can be
/// K_SEM_MAX_LIMIT, re-exported here.
type I = (c_uint, c_uint);
// TODO: Thoughts about how to give parameters to the initialzation.
fn get_wrapped(&self, arg: Self::I) -> Semaphore {
let ptr = self.value.get();
unsafe {
k_sem_init(ptr, arg.0, arg.1);
}
Semaphore {
item: Fixed::Static(ptr),
}
}
}
impl fmt::Debug for Semaphore {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "sys::Semaphore")
}
}