pub struct SpinLock<T, G, I: ResourceInvariant<T> = TrivialResourceInvariant> { /* private fields */ }Expand description
A spin lock.
§Guard behavior
The type `G’ specifies the guard behavior of the spin lock. While holding the lock,
- if
Gis [PreemptDisabled], preemption is disabled; - if
GisLocalIrqDisabled, local IRQs are disabled.
The G can also be provided by other crates other than ostd,
if it behaves similar like [PreemptDisabled] or LocalIrqDisabled.
The guard behavior can be temporarily upgraded from [PreemptDisabled] to
LocalIrqDisabled using the disable_irq method.
§Verified properties
§Ownership model
The lock field extends [AtomicBool] with a [PointsTo<T>] permission and a user-supplied
tracked resource. These two resources are bundled in SpinLockResource and stored as the
atomic ghost state while the lock is available:
tracked struct SpinLockResource<T, I: ResourceInvariant<T>> {
perm: PointsTo<T>,
resource: I::Resource,
}
struct SpinLockInner<T, I: ResourceInvariant<T>> {
lock: AtomicBool<_, Option<SpinLockResource<T, I>>, _>,
val: PCell<T>,
ghost_resource_constant: Ghost<<I as ResourceInvariant<T>>::Constant>,
}When the lock bit is false, the atomic ghost state is Some, the permission refers to val,
and the protected value satisfies the user ResourceInvariant. Acquiring the lock changes
the bit to true and transfers the complete SpinLockResource to the guard, leaving None in
the atomic ghost state. Releasing the guard restores the resource invariant and returns the
bundle to the lock.
The immutable resource constant remains available through ghost_resource_constant even while the
tracked resource is owned by a guard. The complete relationship is encapsulated as a Verus type
invariant; public operations expose only the permissions and resource-invariant facts needed
by their callers.
§Safety
There are no data races.
§Functional Correctness
- At most one user can hold the lock at the same time.
Implementations§
Source§impl<T, G, I: ResourceInvariant<T>> SpinLock<T, G, I>
impl<T, G, I: ResourceInvariant<T>> SpinLock<T, G, I>
Sourcepub const exec fn new(
val: T,
Ghost(resource_constant): Ghost<I::Constant>,
Tracked(resource): Tracked<I::Resource>,
) -> res : Self
pub const exec fn new( val: T, Ghost(resource_constant): Ghost<I::Constant>, Tracked(resource): Tracked<I::Resource>, ) -> res : Self
I::inv(resource_constant, val, resource),ensuresres.constant() == resource_constant,Creates a new spin lock.
§Verified Properties
§Safety
This function is written in safe Rust and there is no undefined behavior.
§Preconditions
None.
§Postconditions
- The function will not panic.
- The created spin lock satisfies the invariant.
Source§impl<T, G, I: ResourceInvariant<T>> SpinLock<T, G, I>
impl<T, G, I: ResourceInvariant<T>> SpinLock<T, G, I>
Source§impl<T, G: SpinGuardian, I: ResourceInvariant<T>> SpinLock<T, G, I>
impl<T, G: SpinGuardian, I: ResourceInvariant<T>> SpinLock<T, G, I>
Sourcepub exec fn lock(&self) -> ret : SpinLockGuard<'_, T, G, I>
pub exec fn lock(&self) -> ret : SpinLockGuard<'_, T, G, I>
ret.constant() == self.constant(),I::inv(ret.constant(), ret.value(), ret.resource()),Acquires the spin lock.
§Verified Properties
§Safety
There are no data races. The lock ensures exclusive access to the protected data.
§Preconditions
None. (The invariant of SpinLock always holds internally.)
§Postconditions
The returned SpinLockGuard satisfies its type invariant and the user-supplied resource
invariant:
- An exclusive permission to access the protected data is held by the guard.
- The guard’s permission matches the lock’s internal cell ID.
- The protected value and tracked resource satisfy the resource invariant.
§Key Verification Step
When the internal atomic compare-and-exchange operation in acquire_lock succeeds,
the ghost permission and user resource are simultaneously extracted from the lock.
atomic_with_ghost! {
self.inner.lock => compare_exchange(false, true);
returning res;
ghost lock_resource => {
// Extract the resources when the lock is successfully acquired.
if res is Ok {
resource = Some(lock_resource.tracked_take());
}
}
}.is_ok()Sourcepub exec fn try_lock(&self) -> ret : Option<SpinLockGuard<'_, T, G, I>>
pub exec fn try_lock(&self) -> ret : Option<SpinLockGuard<'_, T, G, I>>
ret is Some
==> {
&&& ret->0.constant() == self.constant()
&&& I::inv(ret->0.constant(), ret->0.value(), ret->0.resource())
},Tries acquiring the spin lock immediately.
§Verified Properties
§Safety
There are no data races. The lock ensures exclusive access to the protected data.
§Preconditions
None. (The invariant of SpinLock always holds internally.)
§Postconditions
If Some(guard) is returned, it satisfies its type invariant:
- An exclusive permission to access the protected data is held by the guard.
- The guard’s permission matches the lock’s internal cell ID.
Trait Implementations§
impl<T: Send, G, I: ResourceInvariant<T>> Send for SpinLock<T, G, I>
impl<T: Send, G, I: ResourceInvariant<T>> Sync for SpinLock<T, G, I>
Auto Trait Implementations§
impl<T, G, I = TrivialResourceInvariant> !Freeze for SpinLock<T, G, I>
impl<T, G, I = TrivialResourceInvariant> !RefUnwindSafe for SpinLock<T, G, I>
impl<T, G, I> Unpin for SpinLock<T, G, I>where
G: Unpin,
<I as ResourceInvariant<T>>::Constant: Unpin,
T: Unpin,
<I as ResourceInvariant<T>>::Resource: Unpin,
I: Unpin,
impl<T, G, I> UnsafeUnpin for SpinLock<T, G, I>where
T: UnsafeUnpin,
impl<T, G, I> UnwindSafe for SpinLock<T, G, I>where
G: UnwindSafe,
<I as ResourceInvariant<T>>::Constant: UnwindSafe,
T: UnwindSafe + RefUnwindSafe,
<I as ResourceInvariant<T>>::Resource: UnwindSafe + RefUnwindSafe,
I: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Conv for T
impl<T> Conv for T
§impl<T> FmtForward for T
impl<T> FmtForward for T
§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.§fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
§impl<T, VERUS_SPEC__A> FromSpec<T> for VERUS_SPEC__Awhere
VERUS_SPEC__A: From<T>,
impl<T, VERUS_SPEC__A> FromSpec<T> for VERUS_SPEC__Awhere
VERUS_SPEC__A: From<T>,
fn obeys_from_spec() -> bool
fn from_spec(v: T) -> VERUS_SPEC__A
§impl<T, VERUS_SPEC__A> IntoSpec<T> for VERUS_SPEC__Awhere
VERUS_SPEC__A: Into<T>,
impl<T, VERUS_SPEC__A> IntoSpec<T> for VERUS_SPEC__Awhere
VERUS_SPEC__A: Into<T>,
fn obeys_into_spec() -> bool
fn into_spec(self) -> T
§impl<T, U> IntoSpecImpl<U> for Twhere
U: From<T>,
impl<T, U> IntoSpecImpl<U> for Twhere
U: From<T>,
fn obeys_into_spec() -> bool
fn into_spec(self) -> U
§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read more§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read more§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.impl<A> SpecEq<&A> for Awhere
A: ?Sized,
impl<A> SpecEq<&mut A> for Awhere
A: ?Sized,
impl<A> SpecEq<A> for Awhere
A: ?Sized,
impl<A> SpecEq<Ghost<A>> for A
impl<A> SpecEq<Tracked<A>> for A
§impl<T> Tap for T
impl<T> Tap for T
§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read more§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read more§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read more§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read more§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read more§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read more§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.