SpinNoIrq
Relevant source files
SpinNoIrq is the full-protection spinlock implementation in the kspin crate that provides maximum safety by disabling both kernel preemption and local interrupts during lock acquisition and critical sections. This is the safest but most performance-intensive spinlock variant, designed for use in IRQ-enabled contexts where complete isolation is required.
For information about lighter-weight spinlock variants, see SpinRaw and SpinNoPreempt. For comprehensive usage guidelines across all spinlock types, see Usage Guidelines and Safety.
Type Definition and Core Components
SpinNoIrq is implemented as a type alias that specializes the generic BaseSpinLock with the NoPreemptIrqSave guard type from the kernel_guard crate.
flowchart TD
subgraph subGraph0["SpinNoIrq Type System"]
SpinNoIrq["SpinNoIrq<T>Type alias"]
BaseSpinLock["BaseSpinLock<NoPreemptIrqSave, T>Generic implementation"]
SpinNoIrqGuard["SpinNoIrqGuard<'a, T>RAII guard"]
BaseSpinLockGuard["BaseSpinLockGuard<'a, NoPreemptIrqSave, T>Generic guard"]
NoPreemptIrqSave["NoPreemptIrqSavekernel_guard protection"]
end
BaseSpinLock --> NoPreemptIrqSave
BaseSpinLockGuard --> NoPreemptIrqSave
SpinNoIrq --> BaseSpinLock
SpinNoIrqGuard --> BaseSpinLockGuard
The core type definitions establish the relationship between the public API and the underlying implementation:
| Component | Definition | Purpose |
|---|---|---|
| SpinNoIrq | BaseSpinLock<NoPreemptIrqSave, T> | Main spinlock type for data of typeT |
| SpinNoIrqGuard<'a, T> | BaseSpinLockGuard<'a, NoPreemptIrqSave, T> | RAII guard providing mutable access to protected data |
Sources: src/lib.rs(L24 - L27)
Protection Mechanism
SpinNoIrq implements a dual-protection mechanism that addresses both concurrency sources in kernel environments: task preemption and interrupt handling.
sequenceDiagram
participant CallingThread as "Calling Thread"
participant SpinNoIrq as "SpinNoIrq"
participant NoPreemptIrqSave as "NoPreemptIrqSave"
participant KernelScheduler as "Kernel Scheduler"
participant InterruptController as "Interrupt Controller"
CallingThread ->> SpinNoIrq: lock()
SpinNoIrq ->> NoPreemptIrqSave: acquire()
NoPreemptIrqSave ->> KernelScheduler: disable_preemption()
NoPreemptIrqSave ->> InterruptController: save_and_disable_irqs()
Note over CallingThread,InterruptController: Critical Section<br>- No task switches possible<br>- No interrupts delivered<br>- Complete isolation
SpinNoIrq ->> CallingThread: SpinNoIrqGuard
CallingThread ->> CallingThread: /* access protected data */
CallingThread ->> SpinNoIrq: drop(guard)
SpinNoIrq ->> NoPreemptIrqSave: release()
NoPreemptIrqSave ->> InterruptController: restore_irqs()
NoPreemptIrqSave ->> KernelScheduler: enable_preemption()
The protection mechanism operates through the NoPreemptIrqSave guard which:
- Disables Preemption: Prevents the kernel scheduler from switching to other tasks
- Saves and Disables IRQs: Stores current interrupt state and disables local interrupts
- Provides Restoration: Automatically restores the previous state when the guard is dropped
Sources: src/lib.rs(L20 - L23)
Usage Patterns
SpinNoIrq is designed for scenarios requiring complete protection and can be safely used in any kernel context.
Safe Contexts
flowchart TD
subgraph subGraph1["SpinNoIrq Usage"]
SpinNoIrqLock["SpinNoIrq::lock()"]
CriticalSection["Protected Critical Section"]
AutoRestore["Automatic State Restoration"]
end
subgraph subGraph0["Kernel Contexts Where SpinNoIrq is Safe"]
IRQEnabled["IRQ-EnabledKernel Code"]
IRQDisabled["IRQ-DisabledKernel Code"]
SyscallHandler["System CallHandlers"]
TimerContext["Timer/SoftirqContext"]
InitCode["InitializationCode"]
end
CriticalSection --> AutoRestore
IRQDisabled --> SpinNoIrqLock
IRQEnabled --> SpinNoIrqLock
InitCode --> SpinNoIrqLock
SpinNoIrqLock --> CriticalSection
SyscallHandler --> SpinNoIrqLock
TimerContext --> SpinNoIrqLock
Typical Usage Pattern
The standard usage follows the RAII pattern where the guard automatically manages protection state:
| Operation | Effect | Automatic Behavior |
|---|---|---|
| SpinNoIrq::new(data) | Creates protected spinlock | None |
| lock.lock() | Acquires lock | Disables preemption + IRQs |
| Guard in scope | Access to protected data | Maintains protection |
| drop(guard) | Releases lock | Restores preemption + IRQ state |
Sources: README.md(L29 - L33)
Safety Guarantees
SpinNoIrq provides the strongest safety guarantees among all spinlock variants in the kspin crate.
Protection Matrix
| Threat Vector | SpinNoIrq Protection | Mechanism |
|---|---|---|
| Task Preemption | ✅ Complete Protection | NoPreemptcomponent disables scheduler |
| Hardware Interrupts | ✅ Complete Protection | IrqSavecomponent disables IRQs |
| Nested Lock Acquisition | ✅ Deadlock Prevention | IRQ disabling prevents interrupt-based nesting |
| Data Race Conditions | ✅ Mutual Exclusion | Atomic lock state + protection barriers |
Context Safety Analysis
flowchart TD
subgraph Reasoning["Reasoning"]
IRQProtection["IRQ disabling providescomplete isolation"]
PreemptProtection["Preemption disablingprevents task switches"]
IRQHandlerIssue["Using in IRQ handleris redundant sinceIRQs already disabled"]
end
subgraph subGraph0["Context Safety for SpinNoIrq"]
AnyContext["Any Kernel Context"]
IRQHandler["Interrupt Handler"]
TaskContext["Task Context"]
SystemCall["System Call"]
SafeResult["✅ Safe to Use"]
UnsafeResult["❌ Not Recommended"]
end
AnyContext --> SafeResult
IRQHandler --> UnsafeResult
SafeResult --> IRQProtection
SafeResult --> PreemptProtection
SystemCall --> SafeResult
TaskContext --> SafeResult
UnsafeResult --> IRQHandlerIssue
Sources: src/lib.rs(L20 - L23)
Performance Considerations
SpinNoIrq trades performance for safety, making it the most expensive but safest option.
Performance Impact Analysis
| Aspect | Impact Level | Details |
|---|---|---|
| Lock Acquisition Overhead | High | IRQ save/restore + preemption control |
| Critical Section Latency | Highest | No interrupts can be serviced |
| System Responsiveness | Significant | Delayed interrupt handling |
| Throughput Impact | Moderate | Depends on critical section duration |
Performance Comparison
flowchart TD
subgraph subGraph1["Trade-off Characteristics"]
Performance["Performance"]
Safety["Safety"]
end
subgraph subGraph0["Relative Performance (Lower is Faster)"]
SpinRaw["SpinRawOverhead: Minimal"]
SpinNoPreempt["SpinNoPreemptOverhead: Low"]
SpinNoIrq["SpinNoIrqOverhead: High"]
end
Performance --> SpinNoIrq
Safety --> SpinNoIrq
SpinNoPreempt --> SpinNoIrq
SpinRaw --> SpinNoPreempt
Sources: src/lib.rs(L20 - L27)
Relationship to Other Spinlock Types
SpinNoIrq sits at the top of the protection hierarchy, providing comprehensive safety at the cost of performance.
Spinlock Hierarchy
flowchart TD
subgraph subGraph1["Usage Context Requirements"]
ManualControl["Manual IRQ/preemption control required"]
IRQDisabledContext["Must be in IRQ-disabled context"]
AnyKernelContext["Can be used in any kernel context"]
end
subgraph subGraph0["kspin Protection Hierarchy"]
SpinRaw["SpinRaw<T>BaseSpinLock<NoOp, T>No protection"]
SpinNoPreempt["SpinNoPreempt<T>BaseSpinLock<NoPreempt, T>Preemption disabled"]
SpinNoIrq["SpinNoIrq<T>BaseSpinLock<NoPreemptIrqSave, T>Preemption + IRQs disabled"]
end
SpinNoIrq --> AnyKernelContext
SpinNoPreempt --> IRQDisabledContext
SpinNoPreempt --> SpinNoIrq
SpinRaw --> ManualControl
SpinRaw --> SpinNoPreempt
Selection Criteria
| Scenario | Recommended Type | Rationale |
|---|---|---|
| General kernel code | SpinNoIrq | Maximum safety, acceptable overhead |
| Performance-critical paths with manual control | SpinRaw | Minimal overhead when protection already handled |
| IRQ-disabled contexts | SpinNoPreempt | Balanced protection without redundant IRQ control |
| Uncertain context or shared between contexts | SpinNoIrq | Safe default choice |