prove: WaitQueue num_wakers - #702
Conversation
|
I've skimmed through the code, and it looks very interesting. We are busy with other business for now, so we can only review the code closely next week. Please keep in touch! |
|
Please also take a short look at #[repr(transparent)]
#[allow(repr_transparent_non_zst_fields)]
pub struct AtomicDataWithOwner<V, Own> {
/// The underlying data.
pub data: V,
/// The permission to access the data.
pub permission: Tracked<Own>,
}You can also add prediate over it: impl<V, Own: Predicate<V>> Inv for AtomicDataWithOwner<V, Own> {
#[verifier::inline]
open spec fn inv(self) -> bool {
&&& self.permission.predicate(self.data)
}
}One thing I'm not sure is whether we'd favor a struct parameterized by |
|
Hi! Thank you for your feedback. I took a look at Currently, the spin lock deliberately separates the stable predicate To use Please let me know if I have misunderstood the intended use of |
Verified that num_wakers in WaitQueue equals wakers length inside the SpinLock
Add support for user-supplied
SpinLockinvariants and use it to verify thatWaitQueue::num_wakersmatches the number of entries in its protectedVecDequewhenever the spin lock is released.Verification design
SpinLocknow accepts a predicate type:where
P: SpinLockPredicate<T>defines:The lock’s atomic ghost state owns a
SpinLockResourcecontaining:PointsTo<T>permission for the protected value.P::State.The internal invariant has two states:
A successful
lock()transfers both resources to the guard and ensures the predicate initially holds. BeforeSpinLockGuard::drop()can return the resources, the caller must restore the predicate.Existing
SpinLockusers continue to useTrivialSpinLockPredicate, whose state is()and whose invariant is always true.WaitQueue invariant
WaitQueueuses a pair of linked ghost tokens:The spin-lock predicate establishes:
The
num_wakersatomic invariant establishes:Because
GhostVarAuthandGhostVarwith the same ID must agree:This relationship is required whenever the spin lock is unlocked.
Queue updates
When adding or removing a waker:
VecDeque.num_wakersatomic invariant.For successful
pop_front()operations, the queue invariant proves that the previous counter was positive. This removes the previous decrement assumptions.Additional fixes
The change explicitly releases the manually-dropped spin-lock guard on all paths, including:
wake_oneandwake_allpaths.enqueue.Without these calls, the verified spin-lock implementation would remain locked because its ordinary Rust
Dropimplementation is currently disabled.WaitQueue::is_emptyis also verified directly and no longer requires#[verifier::external_body].Verification
The following checks pass:
Remaining limitations
This does not make all of
wait.rsassumption-free. In particular:enqueuestill assumes thatnum_wakersdoes not exceedu32::MAX.wake_allstill assumes thatnum_wokendoes not overflowusize.admit()calls remain.