Skip to content

Commit 46113b1

Browse files
committed
zephyr: sys::sync: move semaphores into their own module
In preparation for adding more synchronization primitives, move the Semaphore implementation into its own module. There is enough stuff associated with each primitive that it can be confusing if they are not in their own modules. Signed-off-by: David Brown <[email protected]>
1 parent 5eb7283 commit 46113b1

File tree

3 files changed

+324
-113
lines changed

3 files changed

+324
-113
lines changed

zephyr/src/sys/sync.rs

Lines changed: 12 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -30,117 +30,16 @@
3030
//! Later, there will be a pool mechanism to allow these kernel objects to be allocated and freed
3131
//! from a pool, although the objects will still be statically allocated.
3232
33-
use core::ffi::c_uint;
34-
use core::fmt;
35-
36-
use crate::{
37-
error::{Result, to_result_void},
38-
object::{StaticKernelObject, Wrapped},
39-
raw::{
40-
k_sem,
41-
k_sem_init,
42-
k_sem_take,
43-
k_sem_give,
44-
k_sem_reset,
45-
k_sem_count_get,
46-
},
47-
time::Timeout,
33+
pub mod mutex;
34+
pub mod semaphore;
35+
36+
pub use mutex::{
37+
Condvar,
38+
StaticCondvar,
39+
Mutex,
40+
StaticMutex,
41+
};
42+
pub use semaphore::{
43+
Semaphore,
44+
StaticSemaphore,
4845
};
49-
50-
pub use crate::raw::K_SEM_MAX_LIMIT;
51-
52-
/// A zephyr `k_sem` usable from safe Rust code.
53-
#[derive(Clone)]
54-
pub struct Semaphore {
55-
/// The raw Zephyr `k_sem`.
56-
item: *mut k_sem,
57-
}
58-
59-
/// By nature, Semaphores are both Sync and Send. Safety is handled by the underlying Zephyr
60-
/// implementation (which is why Clone is also implemented).
61-
unsafe impl Sync for Semaphore {}
62-
unsafe impl Send for Semaphore {}
63-
64-
impl Semaphore {
65-
/// Take a semaphore.
66-
///
67-
/// Can be called from ISR if called with [`NoWait`].
68-
///
69-
/// [`NoWait`]: crate::time::NoWait
70-
pub fn take<T>(&self, timeout: T) -> Result<()>
71-
where T: Into<Timeout>,
72-
{
73-
let timeout: Timeout = timeout.into();
74-
let ret = unsafe {
75-
k_sem_take(self.item, timeout.0)
76-
};
77-
to_result_void(ret)
78-
}
79-
80-
/// Give a semaphore.
81-
///
82-
/// This routine gives to the semaphore, unless the semaphore is already at its maximum
83-
/// permitted count.
84-
pub fn give(&self) {
85-
unsafe {
86-
k_sem_give(self.item)
87-
}
88-
}
89-
90-
/// Resets a semaphor's count to zero.
91-
///
92-
/// This resets the count to zero. Any outstanding [`take`] calls will be aborted with
93-
/// `Error(EAGAIN)`.
94-
///
95-
/// [`take`]: Self::take
96-
pub fn reset(&mut self) {
97-
unsafe {
98-
k_sem_reset(self.item)
99-
}
100-
}
101-
102-
/// Get a semaphore's count.
103-
///
104-
/// Returns the current count.
105-
pub fn count_get(&mut self) -> usize {
106-
unsafe {
107-
k_sem_count_get(self.item) as usize
108-
}
109-
}
110-
}
111-
112-
/// A static Zephyr `k_sem`.
113-
///
114-
/// This is intended to be used from within the `kobj_define!` macro. It declares a static ksem
115-
/// that will be properly registered with the Zephyr kernel object system. Call [`init_once`] to
116-
/// get the [`Semaphore`] that is represents.
117-
///
118-
/// [`init_once`]: StaticKernelObject::init_once
119-
pub type StaticSemaphore = StaticKernelObject<k_sem>;
120-
121-
unsafe impl Sync for StaticSemaphore {}
122-
123-
impl Wrapped for StaticKernelObject<k_sem> {
124-
type T = Semaphore;
125-
126-
/// The initializer for Semaphores is the initial count, and the count limit (which can be
127-
/// K_SEM_MAX_LIMIT, re-exported here.
128-
type I = (c_uint, c_uint);
129-
130-
// TODO: Thoughts about how to give parameters to the initialzation.
131-
fn get_wrapped(&self, arg: Self::I) -> Semaphore {
132-
let ptr = self.value.get();
133-
unsafe {
134-
k_sem_init(ptr, arg.0, arg.1);
135-
}
136-
Semaphore {
137-
item: ptr,
138-
}
139-
}
140-
}
141-
142-
impl fmt::Debug for Semaphore {
143-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144-
write!(f, "sys::Semaphore")
145-
}
146-
}

zephyr/src/sys/sync/mutex.rs

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

0 commit comments

Comments
 (0)