Skip to content

Commit 40c76c2

Browse files
committed
Merge branch 'critical' into tasks-pre
2 parents edcef3b + a4df841 commit 40c76c2

File tree

3 files changed

+35
-21
lines changed

3 files changed

+35
-21
lines changed

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/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
}

0 commit comments

Comments
 (0)