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")
    }
}