@@ -130,11 +130,6 @@ impl<T> Drop for SpinLockGuard<'_, T> {
130130}
131131
132132// RAW SPINLOCK (no interrupt disable, for when you manage it yourself)
133-
134- /// Raw spinlock without interrupt management.
135- ///
136- /// Use when you're already in an interrupt-disabled context or
137- /// don't need interrupt safety.
138133pub struct RawSpinLock {
139134 locked : AtomicBool ,
140135}
@@ -167,6 +162,93 @@ impl RawSpinLock {
167162 }
168163}
169164
165+ // ISR-SAFE RAW SPINLOCK — disables interrupts before acquiring, restores on release.
166+ // Uses per-core saved-IF storage so nested/cross-core usage is correct.
167+ // Max 64 cores. Core index from gs:[0x00] (per-CPU area set up by ap_boot).
168+
169+ pub struct IsrSafeRawSpinLock {
170+ locked : AtomicBool ,
171+ /// Per-core saved IF state. Index = core index (0..MAX_CORES).
172+ /// Only the core that holds the lock reads/writes its own slot.
173+ saved_if : [ core:: cell:: UnsafeCell < bool > ; 64 ] ,
174+ }
175+
176+ // multiple cores touch disjoint slots — safe by construction.
177+ unsafe impl Sync for IsrSafeRawSpinLock { }
178+ unsafe impl Send for IsrSafeRawSpinLock { }
179+
180+ impl IsrSafeRawSpinLock {
181+ pub const fn new ( ) -> Self {
182+ // const init: can't use array::from_fn in const, unroll via macro
183+ const CELL_FALSE : core:: cell:: UnsafeCell < bool > = core:: cell:: UnsafeCell :: new ( false ) ;
184+ Self {
185+ locked : AtomicBool :: new ( false ) ,
186+ saved_if : [ CELL_FALSE ; 64 ] ,
187+ }
188+ }
189+
190+ #[ inline( always) ]
191+ fn core_index ( ) -> usize {
192+ // before per-CPU area is set up, gs base is 0 and this reads 0 (BSP)
193+ let idx: u32 ;
194+ unsafe {
195+ core:: arch:: asm!(
196+ "mov {0:e}, gs:[0x00]" ,
197+ out( reg) idx,
198+ options( nostack, readonly, preserves_flags)
199+ ) ;
200+ }
201+ ( idx as usize ) & 63
202+ }
203+
204+ pub fn lock ( & self ) {
205+ let was_enabled = interrupts_enabled ( ) ;
206+ disable_interrupts ( ) ;
207+
208+ while self
209+ . locked
210+ . compare_exchange_weak ( false , true , Ordering :: Acquire , Ordering :: Relaxed )
211+ . is_err ( )
212+ {
213+ core:: hint:: spin_loop ( ) ;
214+ }
215+
216+ // save per-core IF state AFTER acquiring — only holder touches its slot
217+ let ci = Self :: core_index ( ) ;
218+ unsafe { * self . saved_if [ ci] . get ( ) = was_enabled; }
219+ }
220+
221+ pub fn unlock ( & self ) {
222+ let ci = Self :: core_index ( ) ;
223+ let was_enabled = unsafe { * self . saved_if [ ci] . get ( ) } ;
224+ self . locked . store ( false , Ordering :: Release ) ;
225+
226+ if was_enabled {
227+ enable_interrupts ( ) ;
228+ }
229+ }
230+
231+ pub fn try_lock ( & self ) -> bool {
232+ let was_enabled = interrupts_enabled ( ) ;
233+ disable_interrupts ( ) ;
234+
235+ if self
236+ . locked
237+ . compare_exchange ( false , true , Ordering :: Acquire , Ordering :: Relaxed )
238+ . is_ok ( )
239+ {
240+ let ci = Self :: core_index ( ) ;
241+ unsafe { * self . saved_if [ ci] . get ( ) = was_enabled; }
242+ true
243+ } else {
244+ if was_enabled {
245+ enable_interrupts ( ) ;
246+ }
247+ false
248+ }
249+ }
250+ }
251+
170252// ONCE (run-once initialization)
171253
172254/// Run-once initialization primitive.
@@ -218,8 +300,6 @@ impl Once {
218300 }
219301}
220302
221- // LAZY (lazily initialized value)
222-
223303/// Lazily initialized value.
224304pub struct Lazy < T , F = fn ( ) -> T > {
225305 once : Once ,
@@ -259,8 +339,6 @@ impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> {
259339 }
260340}
261341
262- // INTERRUPT GUARD
263-
264342/// RAII guard that disables interrupts and restores on drop.
265343pub struct InterruptGuard {
266344 was_enabled : bool ,
0 commit comments