Skip to main content

SpinLockIrq

Type Alias SpinLockIrq 

Source
pub type SpinLockIrq<T> = Lock<T, SpinLockIrqBackend>;
Expand description

A variant of SpinLock that ensures interrupts are disabled in the critical section.

This lock can be acquired in two ways:

  • Using lock() like any other type of lock, in which case the bindings will modify the interrupt state to ensure that local processor interrupts remain disabled for at least as long as the SpinLockIrqGuard exists.
  • Using lock_with() in contexts where a LocalInterruptDisabled token is present and local processor interrupts are already known to be disabled, in which case the local interrupt state will not be touched. This method should be preferred if a LocalInterruptDisabled token is present in the scope.

For more info on spinlocks, see SpinLock. For more information on interrupts, see the interrupt module.

§Examples

The following example shows how to declare, allocate initialise and access a struct (Example) that contains an inner struct (Inner) that is protected by a spinlock that requires local processor interrupts to be disabled.

use kernel::sync::{new_spinlock_irq, SpinLockIrq};

struct Inner {
    a: u32,
    b: u32,
}

#[pin_data]
struct Example {
    #[pin]
    c: SpinLockIrq<Inner>,
    #[pin]
    d: SpinLockIrq<Inner>,
}

impl Example {
    fn new() -> impl PinInit<Self> {
        pin_init!(Self {
            c <- new_spinlock_irq!(Inner { a: 0, b: 10 }),
            d <- new_spinlock_irq!(Inner { a: 20, b: 30 }),
        })
    }
}

// Allocate a boxed `Example`
let e = KBox::pin_init(Example::new(), GFP_KERNEL)?;

// Accessing an `Example` from a context where interrupts may not be disabled already.
let c_guard = e.c.lock(); // interrupts are disabled now, +1 interrupt disable refcount
let d_guard = e.d.lock(); // no interrupt state change, +1 interrupt disable refcount

assert_eq!(c_guard.a, 0);
assert_eq!(c_guard.b, 10);
assert_eq!(d_guard.a, 20);
assert_eq!(d_guard.b, 30);

drop(c_guard); // Dropping c_guard will not re-enable interrupts just yet, since d_guard is
               // still in scope.
drop(d_guard); // Last interrupt disable reference dropped here, so interrupts are re-enabled
               // now

The next example demonstrates locking a SpinLockIrq using lock_with() in a function which can only be called when local processor interrupts are already disabled.

use kernel::sync::{new_spinlock_irq, SpinLockIrq};
use kernel::interrupt::*;

struct Inner {
    a: u32,
}

#[pin_data]
struct Example {
    #[pin]
    inner: SpinLockIrq<Inner>,
}

impl Example {
    fn new() -> impl PinInit<Self> {
        pin_init!(Self {
            inner <- new_spinlock_irq!(Inner { a: 20 }),
        })
    }
}

// Accessing an `Example` from a function that can only be called in no-interrupt contexts.
fn noirq_work(e: &Example, interrupt_disabled: &LocalInterruptDisabled) {
    // Because we know interrupts are disabled from interrupt_disable, we can skip toggling
    // interrupt state using lock_with() and the provided token
    assert_eq!(e.inner.lock_with(interrupt_disabled).a, 20);
}

Aliased Type§

pub struct SpinLockIrq<T> { /* private fields */ }