1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#![no_std]
pub use bare_metal::CriticalSection;
#[inline]
pub unsafe fn acquire() -> u8 {
extern "Rust" {
fn _critical_section_acquire() -> u8;
}
_critical_section_acquire()
}
#[inline]
pub unsafe fn release(token: u8) {
extern "Rust" {
fn _critical_section_release(token: u8);
}
_critical_section_release(token)
}
#[inline]
pub fn with<R>(f: impl FnOnce(CriticalSection) -> R) -> R {
unsafe {
let token = acquire();
let r = f(CriticalSection::new());
release(token);
r
}
}
cfg_if::cfg_if! {
if #[cfg(feature = "custom-impl")] {
pub unsafe trait Impl {
unsafe fn acquire() -> u8;
unsafe fn release(token: u8);
}
#[macro_export]
macro_rules! custom_impl {
($t: ty) => {
#[no_mangle]
unsafe fn _critical_section_acquire() -> u8 {
<$t as $crate::Impl>::acquire()
}
#[no_mangle]
unsafe fn _critical_section_release(token: u8) {
<$t as $crate::Impl>::release(token)
}
};
}
} else if #[cfg(cortex_m)] {
#[no_mangle]
unsafe fn _critical_section_acquire() -> u8 {
let primask = cortex_m::register::primask::read();
cortex_m::interrupt::disable();
primask.is_active() as _
}
#[no_mangle]
unsafe fn _critical_section_release(token: u8) {
if token != 0 {
cortex_m::interrupt::enable()
}
}
} else if #[cfg(target_arch = "riscv32")] {
#[no_mangle]
unsafe fn _critical_section_acquire() -> u8 {
let interrupts_active = riscv::register::mstatus::read().mie();
riscv::interrupt::disable();
interrupts_active as _
}
#[no_mangle]
unsafe fn _critical_section_release(token: u8) {
if token != 0 {
riscv::interrupt::enable();
}
}
} else if #[cfg(any(unix, windows, wasm, target_arch = "wasm32"))] {
extern crate std;
static INIT: std::sync::Once = std::sync::Once::new();
static mut GLOBAL_LOCK: Option<std::sync::Mutex<()>> = None;
static mut GLOBAL_GUARD: Option<std::sync::MutexGuard<'static, ()>> = None;
#[no_mangle]
unsafe fn _critical_section_acquire() -> u8 {
INIT.call_once(|| unsafe {
GLOBAL_LOCK.replace(std::sync::Mutex::new(()));
});
let guard = GLOBAL_LOCK.as_ref().unwrap().lock().unwrap();
GLOBAL_GUARD.replace(guard);
1
}
#[no_mangle]
unsafe fn _critical_section_release(token: u8) {
if token == 1 {
GLOBAL_GUARD.take();
}
}
} else {
compile_error!("Critical section is not implemented for this target. Make sure you've specified the correct --target. You may need to supply a custom critical section implementation with the `custom-impl` feature");
}
}