Skip to content

Commit f9f447c

Browse files
committed
zephyr: sys: Create sys::sync with Mutex
Create the first kernel object wrapper: Mutex, which wraps Zephyr's `k_mutex`. Signed-off-by: David Brown <[email protected]>
1 parent c54e59e commit f9f447c

File tree

2 files changed

+125
-0
lines changed

2 files changed

+125
-0
lines changed

zephyr/src/sys.rs

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
//! This module `zephyr::sys` contains thin wrappers to these C bindings, that can be used without
1010
//! unsafe, but as unchanged as possible.
1111
12+
pub mod sync;
13+
1214
use zephyr_sys::k_timeout_t;
1315

1416
// These two constants are not able to be captured by bindgen. It is unlikely that these values

zephyr/src/sys/sync.rs

+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// Copyright (c) 2024 Linaro LTD
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
//! # Zephyr low-level synchronization primities.
5+
//!
6+
//! The `zephyr-sys` crate contains direct calls into the Zephyr C API. This interface, however,
7+
//! cannot be used from safe Rust. This crate attempts to be as direct an interface to some of
8+
//! these synchronization mechanisms, but without the need for unsafe. The other module
9+
//! `crate::sync` provides higher level interfaces that help manage synchronization in coordination
10+
//! with Rust's borrowing and sharing rules, and will generally provide much more usable
11+
//! interfaces.
12+
//!
13+
//! # Kernel objects
14+
//!
15+
//! Zephyr's primitives work with the concept of a kernel object. These are the data structures
16+
//! that are used by the Zephyr kernel to coordinate the operation of the primitives. In addition,
17+
//! they are where the protection barrier provided by `CONFIG_USERSPACE` is implemented. In order
18+
//! to use these primitives from a userspace thread two things must happen:
19+
//!
20+
//! - The kernel objects must be specially declared. All kernel objects in Zephyr will be built,
21+
//! at compile time, into a perfect hash table that is used to validate them. The special
22+
//! declaration will take care of this.
23+
//! - The objects must be granted permission to be used by the userspace thread. This can be
24+
//! managed either by specifically granting permission, or by using inheritance when creating the
25+
//! thread.
26+
//!
27+
//! At this time, only the first mechanism is implemented, and all kernel objects should be
28+
//! declared using the `crate::kobj_define!` macro. These then must be initialized, and then the
29+
//! special method `.get()` called, to retrieve the Rust-style value that is used to manage them.
30+
//! Later, there will be a pool mechanism to allow these kernel objects to be allocated and freed
31+
//! from a pool, although the objects will still be statically allocated.
32+
33+
use core::fmt;
34+
35+
use crate::raw::{
36+
k_mutex,
37+
k_mutex_init,
38+
k_mutex_lock,
39+
k_mutex_unlock,
40+
};
41+
use crate::object::{
42+
KobjInit,
43+
StaticKernelObject,
44+
};
45+
use crate::time::{
46+
Timeout,
47+
};
48+
49+
/// A Zephyr `k_mutux` usable from safe Rust code.
50+
///
51+
/// This merely wraps a pointer to the kernel object. It implements clone, send and sync as it is
52+
/// safe to have multiple instances of these, as well as use them across multiple threads.
53+
///
54+
/// Note that these are Safe in the sense that memory safety is guaranteed. Attempts to
55+
/// recursively lock, or incorrect nesting can easily result in deadlock.
56+
#[derive(Clone)]
57+
pub struct Mutex {
58+
pub item: *mut k_mutex,
59+
}
60+
61+
unsafe impl Sync for StaticKernelObject<k_mutex> {}
62+
63+
impl KobjInit<k_mutex, Mutex> for StaticKernelObject<k_mutex> {
64+
fn wrap(ptr: *mut k_mutex) -> Mutex {
65+
Mutex { item: ptr }
66+
}
67+
}
68+
69+
impl Mutex {
70+
pub fn lock<T>(&self, timeout: T)
71+
where T: Into<Timeout>,
72+
{
73+
let timeout: Timeout = timeout.into();
74+
// TODO: Erro
75+
unsafe { k_mutex_lock(self.item, timeout.0); }
76+
}
77+
78+
pub fn unlock(&self) {
79+
unsafe { k_mutex_unlock(self.item); }
80+
}
81+
}
82+
83+
unsafe impl Sync for Mutex {}
84+
unsafe impl Send for Mutex {}
85+
86+
impl fmt::Debug for Mutex {
87+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88+
write!(f, "sys::Mutex {:?}", self.item)
89+
}
90+
}
91+
92+
/// A static Zephyr `k_mutex`.
93+
///
94+
/// This is intended to be used from within the `kobj_define!` macro. It declares a static mutex
95+
/// that will be properly registered with the Zephyr kernel object system. The `init` method must
96+
/// be called before `get`.
97+
///
98+
/// ```
99+
/// kobj_define! {
100+
/// static SINGLE: StaticMutex;
101+
/// static MULTIPLE: [StaticMutex; 4];
102+
/// }
103+
///
104+
/// let multiple MULTIPLE.each_ref().map(|m| {
105+
/// m.init();
106+
/// m.get()
107+
/// });
108+
///
109+
/// SINGLE.init();
110+
/// let single = SINGLE.get();
111+
/// ...
112+
/// ```
113+
pub type StaticMutex = StaticKernelObject<k_mutex>;
114+
115+
impl StaticMutex {
116+
pub fn init(&self) {
117+
self.init_help(|raw| {
118+
unsafe {
119+
k_mutex_init(raw);
120+
}
121+
})
122+
}
123+
}

0 commit comments

Comments
 (0)