pub struct SpinLock<T: ?Sized> { /* private fields */ }
Expand description
Exposes the kernel’s spinlock_t
. When multiple CPUs attempt to lock the same spinlock, only
one at a time is allowed to progress, the others will block (spinning) until the spinlock is
unlocked, at which point another CPU will be allowed to make progress.
A SpinLock
must first be initialised with a call to SpinLock::init_lock
before it can be
used. The spinlock_init
macro is provided to automatically assign a new lock class to a
spinlock instance.
There are two ways to acquire the lock:
SpinLock::lock
, which doesn’t manage interrupt state, so it should be used in only two cases: (a) when the caller knows that interrupts are disabled, or (b) when callers never use it in atomic context (e.g., interrupt handlers), in which case it is ok for interrupts to be enabled.SpinLock::lock_irqdisable
, which disables interrupts if they are enabled before acquiring the lock. When the lock is released, the interrupt state is automatically returned to its value beforeSpinLock::lock_irqdisable
was called.
Examples
struct Example {
a: u32,
b: u32,
}
// Function that acquires spinlock without changing interrupt state.
fn lock_example(value: &SpinLock<Example>) {
let mut guard = value.lock();
guard.a = 10;
guard.b = 20;
}
// Function that acquires spinlock and disables interrupts while holding it.
fn lock_irqdisable_example(value: &SpinLock<Example>) {
let mut guard = value.lock_irqdisable();
guard.a = 30;
guard.b = 40;
}
// Initialises a spinlock.
// SAFETY: `spinlock_init` is called below.
let mut value = unsafe { SpinLock::new(Example { a: 1, b: 2 }) };
// SAFETY: We don't move `value`.
kernel::spinlock_init!(unsafe { Pin::new_unchecked(&mut value) }, "value");
// Calls the example functions.
assert_eq!(value.lock().a, 1);
lock_example(&value);
assert_eq!(value.lock().a, 10);
lock_irqdisable_example(&value);
assert_eq!(value.lock().a, 30);
Implementations
sourceimpl<T> SpinLock<T>
impl<T> SpinLock<T>
sourcepub const unsafe fn new(t: T) -> Self
pub const unsafe fn new(t: T) -> Self
Constructs a new spinlock.
Safety
The caller must call SpinLock::init_lock
before using the spinlock.
sourceimpl<T: ?Sized> SpinLock<T>
impl<T: ?Sized> SpinLock<T>
sourcepub fn lock(&self) -> Guard<'_, Self, WriteLock>
pub fn lock(&self) -> Guard<'_, Self, WriteLock>
Locks the spinlock and gives the caller access to the data protected by it. Only one thread at a time is allowed to access the protected data.
sourcepub fn lock_irqdisable(&self) -> Guard<'_, Self, DisabledInterrupts>
pub fn lock_irqdisable(&self) -> Guard<'_, Self, DisabledInterrupts>
Locks the spinlock and gives the caller access to the data protected by it. Additionally it disables interrupts (if they are enabled).
When the lock in unlocked, the interrupt state (enabled/disabled) is restored.