1use vstd::atomic_ghost::*;
3use vstd::cell::{self, pcell::*};
4use vstd::prelude::*;
5use vstd_extra::resource::ghost_resource::excl::*;
6
7use alloc::sync::Arc;
8use core::{
9 cell::UnsafeCell,
10 fmt,
11 ops::{Deref, DerefMut},
12 sync::atomic::Ordering,
13};
14
15use super::WaitQueue;
16
17verus! {
18
19struct_with_invariants! {
20
21pub struct Mutex<T > {
23 lock: AtomicBool<_, Option<PointsTo<T>>, _>,
24 queue: WaitQueue,
25 val: PCell<T>,
27}
28
29closed spec fn wf(self) -> bool {
30 invariant on lock with (val) is (v: bool, g: Option<PointsTo<T>>) {
31 let active_guard = g is None;
32 &&& v <==> active_guard
33 &&& g is Some ==> g->Some_0.id() == val.id()
34 }
35}
36}
37
38impl<T> Mutex<T> {
39 pub closed spec fn cell_id(self) -> cell::CellId {
40 self.val.id()
41 }
42
43 #[verifier::type_invariant]
44 pub closed spec fn type_inv(self) -> bool {
45 self.wf()
46 }
47
48 pub const fn new(val: T) -> Self {
50 let (val, Tracked(perm)) = PCell::new(val);
51 Self {
52 lock: AtomicBool::new(
53 Ghost(val),
54 false,
55 Tracked(Some(perm)),
56 ),
57 queue: WaitQueue::new(),
58 val: val,
59 }
60 }
61}
62
63#[verus_verify]
64impl<T > Mutex<T> {
65 #[track_caller]
69 pub fn lock(&self) -> MutexGuard<'_, T> {
70 self.queue.wait_until(|| self.try_lock())
71 }
72
73 #[verus_spec]
75 pub fn try_lock(&self) -> Option<MutexGuard<T>> {
76 proof_decl! {
80 let tracked mut locked_state: Option<PointsTo<T>> = None;
81 }
82 {#[verus_spec(with => Tracked(locked_state))] self.acquire_lock()}.then(
83 || requires
84 locked_state is Some,
85 locked_state -> Some_0.id() == self.cell_id(),
86 {unsafe { proof_with!{Tracked(locked_state.tracked_unwrap())};
87 MutexGuard::new(self) }})
88 }
89
90 #[verus_spec(
101 with
102 Tracked(perm): Tracked<PointsTo<T>>,
103 requires
104 perm.id() == self.cell_id(),
105 )]
106 fn unlock(&self)
107 {
108 proof_with!(Tracked(perm));
109 self.release_lock();
110 self.queue.wake_one();
111 }
112
113 #[verus_spec(ret =>
114 with
115 -> locked_state: Tracked<Option<PointsTo<T>>>,
116 ensures
117 ret ==> locked_state@ is Some && locked_state@->Some_0.id() == self.cell_id(),
118 !ret ==> locked_state@ is None,
119 )]
120 fn acquire_lock(&self) -> bool {
121 proof_decl! {
122 let tracked mut locked_state: Option<PointsTo<T>> = None;
123 }
124 proof! {
125 use_type_invariant(self);
126 }
127 proof_with! { |= Tracked(locked_state) }
128 atomic_with_ghost! {
129 self.lock => compare_exchange(false, true);
130 returning res;
131 ghost perms => {
132 if res is Ok {
133 let tracked perm = perms.tracked_take();
134 locked_state = Some(perm);
135 }
136 }
137 }.is_ok()
138 }
139
140 #[verus_spec(
141 with
142 Tracked(perm): Tracked<PointsTo<T>>,
143 requires
144 perm.id() == self.cell_id(),
145 )]
146 fn release_lock(&self)
147 {
148 proof! {
149 use_type_invariant(self);
150 }
151 atomic_with_ghost! {
152 self.lock => store(false);
153 ghost perms => {
154 perms = Some(perm);
155 }
156 }
157 }
158}
159
160#[verifier::external]
167unsafe impl<T: Send> Send for Mutex<T> {}
168#[verifier::external]
169unsafe impl<T: Send> Sync for Mutex<T> {}
170
171#[verifier::reject_recursive_types(T)]
173#[clippy::has_significant_drop]
174#[must_use]
175pub struct MutexGuard<'a, T > {
176 mutex: &'a Mutex<T>,
177 v_perm: Tracked<PointsTo<T>>,
178}
179
180impl<'a, T > MutexGuard<'a, T> {
181 #[verus_spec(ret =>
186 with
187 Tracked(perm): Tracked<PointsTo<T>>,
188 requires
189 perm.id() == mutex.cell_id(),
190 )]
191 unsafe fn new(mutex: &'a Mutex<T>) -> (r: MutexGuard<'a, T>)
192 {
193 MutexGuard { mutex, v_perm: Tracked(perm) }
194 }
195
196 #[verifier::type_invariant]
197 closed spec fn type_inv(self) -> bool {
198 self.v_perm@.id() == self.mutex.cell_id()
199 }
200
201 #[verus_spec]
204 pub fn drop(self) {
205 proof! {
206 use_type_invariant(&self);
207 use_type_invariant(&*self.mutex);
208 }
209 proof_with!{self.v_perm}
210 self.mutex.release_lock();
211 self.mutex.queue.wake_one();
212 }
213}
214
215impl<T> Deref for MutexGuard<'_, T> {
216 type Target = T;
217
218 fn deref(&self) -> &Self::Target {
219 proof! {
220 use_type_invariant(self);
221 }
222 self.mutex.val.borrow(Tracked(self.v_perm.borrow()))
224 }
225}
226
227impl<T > !Send for MutexGuard<'_, T> {}
251
252impl<'a, T > MutexGuard<'a, T> {
254 pub fn get_lock(guard: &MutexGuard<'a, T>) -> &'a Mutex<T> {
256 guard.mutex
257 }
258}
259
260} #[cfg(ktest)]
262mod test {
263 use super::*;
264 use crate::prelude::*;
265
266 #[ktest]
268 fn test_mutex_try_lock_does_not_unlock() {
269 let lock = Mutex::new(0);
270 assert!(!lock.lock.load(Ordering::Relaxed));
271
272 let guard1 = lock.lock();
274 assert!(lock.lock.load(Ordering::Relaxed));
275
276 assert!(lock.try_lock().is_none());
278 assert!(lock.lock.load(Ordering::Relaxed));
279
280 drop(guard1);
282 }
283}