Skip to content

Commit 2bb4174

Browse files
authored
Merge branch 'zephyrproject-rtos:main' into check-cfg
2 parents d1957c9 + e53f6de commit 2bb4174

File tree

6 files changed

+55
-30
lines changed

6 files changed

+55
-30
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ ${module}.path = \"$CACHE{RUST_MODULE_DIR}/${module}\"
129129
# symlink) in the source directory to allow various IDE tools and such to work. The build we
130130
# invoke will override these settings, in case they are out of date. Everything set here
131131
# should match the arguments given to the cargo build command below.
132-
file(WRITE ${SAMPLE_CARGO_CONFIG} "
132+
file(GENERATE OUTPUT ${SAMPLE_CARGO_CONFIG} CONTENT "
133133
# This is a generated sample .cargo/config.toml file from the Zephyr build.
134134
# At the time of generation, this represented the settings needed to allow
135135
# a `cargo build` command to compile the rust code using the current Zephyr build.

zephyr-sys/build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ fn main() -> Result<()> {
7777
.allowlist_function("k_.*")
7878
.allowlist_function("gpio_.*")
7979
.allowlist_function("flash_.*")
80+
.allowlist_function("zr_.*")
8081
.allowlist_item("GPIO_.*")
8182
.allowlist_item("FLASH_.*")
8283
.allowlist_item("Z_.*")

zephyr-sys/wrapper.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ extern int errno;
4242
#include <zephyr/logging/log.h>
4343
#include <zephyr/bluetooth/bluetooth.h>
4444
#include <zephyr/drivers/flash.h>
45+
#include <zephyr/irq.h>
4546

4647
/*
4748
* bindgen will only output #defined constants that resolve to simple numbers. These are some
@@ -61,3 +62,15 @@ const uint32_t ZR_POLL_TYPE_DATA_AVAILABLE = K_POLL_TYPE_DATA_AVAILABLE;
6162
const uint32_t ZR_GPIO_INT_MODE_DISABLE_ONLY = GPIO_INT_MODE_DISABLE_ONLY;
6263
const uint32_t ZR_GPIO_INT_MODE_ENABLE_ONLY = GPIO_INT_MODE_ENABLE_ONLY;
6364
#endif
65+
66+
/*
67+
* Zephyr's irq_lock() and irq_unlock() are macros not inline functions, so we need some inlines to
68+
* access them.
69+
*/
70+
static inline int zr_irq_lock(void) {
71+
return irq_lock();
72+
}
73+
74+
static inline void zr_irq_unlock(int key) {
75+
irq_unlock(key);
76+
}

zephyr/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ description = """
99
Functionality for Rust-based applications that run on Zephyr.
1010
"""
1111

12+
# 1.85 is needed to support working with or without edition 2024.
13+
rust-version = "1.85"
14+
1215
[dependencies]
1316
zephyr-sys = { version = "0.1.0", path = "../zephyr-sys" }
1417
zephyr-macros = { version = "0.1.0", path = "../zephyr-macros" }

zephyr/src/sys.rs

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -39,42 +39,42 @@ pub fn uptime_get() -> i64 {
3939
unsafe { crate::raw::k_uptime_get() }
4040
}
4141

42+
// The below implementation, based on interrupt locking has only been tested on single CPU. The
43+
// implementation suggests it should work on SMP, and can be tested. The docs for irq_lock()
44+
// explicitly state that it cannot be used from userspace. Unfortunately, spinlocks have
45+
// incompatible semantics with critical sections, so to work with userspace we'd need probably a
46+
// syscall.
47+
#[cfg(CONFIG_USERSPACE)]
48+
compile_error!("Critical-section implementation does not work with CONFIG_USERSPACE");
49+
4250
pub mod critical {
4351
//! Zephyr implementation of critical sections.
4452
//!
45-
//! Critical sections from Rust are handled with a single Zephyr spinlock. This doesn't allow
46-
//! any nesting, but neither does the `critical-section` crate.
47-
//!
48-
//! This provides the underlying critical section crate, which is useful for external crates
49-
//! that want this interface. However, it isn't a particularly hygienic interface to use. For
50-
//! something a bit nicer, please see [`sync::SpinMutex`].
51-
//!
52-
//! [`sync::SpinMutex`]: crate::sync::SpinMutex
53+
//! The critical-section crate explicitly states that critical sections can be nested.
54+
//! Unfortunately, Zephyr spinlocks cannot be nested. It is possible to nest different ones,
55+
//! but the critical-section implementation API doesn't give access to the stack.
5356
54-
use core::{ffi::c_int, ptr::addr_of_mut};
57+
use core::{
58+
ffi::c_int,
59+
sync::atomic::{fence, Ordering},
60+
};
5561

5662
use critical_section::RawRestoreState;
57-
use zephyr_sys::{k_spin_lock, k_spin_unlock, k_spinlock, k_spinlock_key_t};
63+
use zephyr_sys::{zr_irq_lock, zr_irq_unlock};
5864

5965
struct ZephyrCriticalSection;
6066
critical_section::set_impl!(ZephyrCriticalSection);
6167

62-
// The critical section shares a single spinlock.
63-
static mut LOCK: k_spinlock = unsafe { core::mem::zeroed() };
64-
6568
unsafe impl critical_section::Impl for ZephyrCriticalSection {
6669
unsafe fn acquire() -> RawRestoreState {
67-
let res = k_spin_lock(addr_of_mut!(LOCK));
68-
res.key as RawRestoreState
70+
let res = zr_irq_lock();
71+
fence(Ordering::Acquire);
72+
res as RawRestoreState
6973
}
7074

7175
unsafe fn release(token: RawRestoreState) {
72-
k_spin_unlock(
73-
addr_of_mut!(LOCK),
74-
k_spinlock_key_t {
75-
key: token as c_int,
76-
},
77-
);
76+
fence(Ordering::Release);
77+
zr_irq_unlock(token as c_int);
7878
}
7979
}
8080
}

zephyr/src/thread.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ use zephyr_sys::{
2424

2525
use crate::{
2626
align::AlignAs,
27+
error::to_result_void,
2728
sys::{K_FOREVER, K_NO_WAIT},
29+
time::{Forever, Timeout},
2830
};
2931

3032
/// Adjust a given requested stack size up for the alignment. This is just the stack, and the
@@ -249,20 +251,26 @@ pub struct RunningThread {
249251
}
250252

251253
impl RunningThread {
254+
/// Wait, with timeout, for this thread to finish executing.
255+
///
256+
/// Will block until either the thread terminates, or the timeout occurrs.
257+
pub fn join_timeout<T>(&self, timeout: T) -> crate::Result<()>
258+
where
259+
T: Into<Timeout>,
260+
{
261+
let timeout: Timeout = timeout.into();
262+
let ret = unsafe { k_thread_join(self.id, timeout.0) };
263+
to_result_void(ret)
264+
}
265+
252266
/// Wait for this thread to finish executing.
253267
///
254268
/// Will block until the thread has terminated.
255269
///
256270
/// TODO: Allow a timeout?
257271
/// TODO: Should we try to return a value?
258-
pub fn join(&self) {
259-
unsafe {
260-
// TODO: Can we do something meaningful with the result?
261-
k_thread_join(self.id, K_FOREVER);
262-
263-
// TODO: Ideally, we could put the thread state back to avoid the need for another join
264-
// check when re-allocating the thread.
265-
}
272+
pub fn join(&self) -> crate::Result<()> {
273+
self.join_timeout(Forever)
266274
}
267275
}
268276

0 commit comments

Comments
 (0)