Skip to content

Commit 73fb47f

Browse files
committed
zephyr: Replace critical-section implementation
There is a fairly fundamental incompatibility between Zephyr spin locks and the Critical Section specification. Zephyr spin locks do not allow nesting from within a single spin lock. The critical section API only has an `acquire` and `release` entry, and provides no way (such as a stack frame) to have a unique context for different invocation places. Unfortunately, this means we cannot use spin locks for critical sections. Instead, this change implements critical sections using irq locking. The implementation of these macros on Zephyr does try to make them SMP safe, with a simple atomic lock, but this hasn't yet been tested, so there is a compile-time assertion against SMP. Also, these entries cannot be called from user mode. There are various other reasons we don't support usermode, so at this time, just have a compile time assertion that usermode is not enabled in the build. If it is needed, we will have to come up with another way to implement this. Signed-off-by: David Brown <[email protected]>
1 parent 74ec8a8 commit 73fb47f

File tree

1 file changed

+23
-21
lines changed

1 file changed

+23
-21
lines changed

zephyr/src/sys.rs

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -39,42 +39,44 @@ 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+
50+
51+
// For now, assert we are not SMP. Once this can be verified, this can be removed.
52+
#[cfg(CONFIG_SMP)]
53+
compile_error!("TODO: Critical-section implementation not SMP verified");
54+
4255
pub mod critical {
4356
//! Zephyr implementation of critical sections.
4457
//!
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
58+
//! The critical-section crate explicitly states that critical sections can be nested.
59+
//! Unfortunately, Zephyr spinlocks cannot be nested. It is possible to nest different ones,
60+
//! but the critical-section implementation API doesn't give access to the stack.
5361
54-
use core::{ffi::c_int, ptr::addr_of_mut};
62+
use core::{ffi::c_int, sync::atomic::{fence, Ordering}};
5563

5664
use critical_section::RawRestoreState;
57-
use zephyr_sys::{k_spin_lock, k_spin_unlock, k_spinlock, k_spinlock_key_t};
65+
use zephyr_sys::{zr_irq_lock, zr_irq_unlock};
5866

5967
struct ZephyrCriticalSection;
6068
critical_section::set_impl!(ZephyrCriticalSection);
6169

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

7177
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-
);
78+
fence(Ordering::Release);
79+
zr_irq_unlock(token as c_int);
7880
}
7981
}
8082
}

0 commit comments

Comments
 (0)