1use vstd::{
3 atomic_ghost::*,
4 prelude::*,
5 resource::{
6 Loc,
7 ghost_var::{GhostVar, GhostVarAuth},
8 },
9};
10use vstd_extra::resource_invariant::ResourceInvariant;
11
12use super::{LocalIrqDisabled, SpinLock};
13use crate::task::{Task, scheduler};
14use alloc::{collections::VecDeque, sync::Arc};
15use core::intrinsics::atomic_cxchg;
16use core::sync::atomic::{Ordering};
17
18verus! {
47
48struct WakersInvariant;
49
50impl ResourceInvariant<VecDeque<Arc<Waker>>> for WakersInvariant {
51 type Constant = Loc;
52
53 type Resource = GhostVar<int>;
54
55 closed spec fn inv(ghost_id: Loc, wakers: VecDeque<Arc<Waker>>, mirror: GhostVar<int>) -> bool {
59 &&& mirror.id() == ghost_id
60 &&& mirror@ == wakers@.len()
61 }
62}
63
64struct_with_invariants! {
65
66pub struct WaitQueue {
73 num_wakers: AtomicU32<_, GhostVarAuth<int>, _>,
75 wakers: SpinLock<VecDeque<Arc<Waker>>, LocalIrqDisabled, WakersInvariant>,
76}
77
78closed spec fn wf(self) -> bool {
79 invariant on num_wakers with (wakers) is (v: u32, g: GhostVarAuth<int>) {
82 &&& g.id() == wakers.constant()
83 &&& g@ == v
84 }
85}
86}
87
88impl WaitQueue {
89 #[verifier::type_invariant]
90 pub closed spec fn type_inv(self) -> bool {
91 self.wf()
92 }
93}
94
95impl WaitQueue {
96 pub const fn new() -> Self {
98 proof_decl! {
99 let tracked (count_auth, count_mirror) = GhostVarAuth::<int>::new(0int);
100 let ghost ghost_id = count_auth.id();
101 }
102 let wakers = SpinLock::new(VecDeque::new(), Ghost(ghost_id), Tracked(count_mirror));
103 WaitQueue { num_wakers: AtomicU32::new(Ghost(wakers), 0, Tracked(count_auth)), wakers }
104 }
105
106 #[track_caller]
117 #[verus_spec(ret =>
118 requires
119 cond.requires(()),
120 ensures
121 cond.ensures((), Some(ret)),
122 )]
123 #[verifier::exec_allows_no_decreases_clause]
124 pub fn wait_until<F, R>(&self, mut cond: F) -> R where F: FnMut() -> Option<R> {
125 if let Some(res) = cond() {
126 return res;
127 }
128 let (waiter, _) = Waiter::new_pair();
129 #[verus_spec(invariant
130 cond.requires(()),
131 )]
132 loop {
133 self.enqueue(waiter.waker());
134 if let Some(res) = cond() {
135 assert(cond.ensures((), Some(res)));
136 proof! { admit(); } return res;
138 }
139 waiter.wait();
140 }
141 }
142
143 #[verifier::exec_allows_no_decreases_clause]
146 pub fn wake_one(&self) -> (r: bool) {
147 proof!{
148 use_type_invariant(self);
149 }
150
151 if self.is_empty() {
153 return false;
154 }
155 loop
156 invariant
157 self.wf(),
158 {
159 let mut wakers = self.wakers.lock();
160 let Some(waker) = wakers.pop_front() else {
161 wakers.drop();
162 return false;
163 };
164 proof_decl!{
165 let tracked count_mirror = wakers.tracked_borrow_mut_resource();
166 }
167 atomic_with_ghost! {
168 self.num_wakers => fetch_sub(1);
169 update prev -> next;
170 ghost count_auth => {
171 count_auth.agree(&*count_mirror);
172 assert(prev == count_mirror@);
173 assert(prev > 0);
174 count_auth.update(count_mirror, next);
175 }
176 };
177 wakers.drop();
180
181 if waker.wake_up() {
182 return true;
183 }
184 }
185 }
186
187 #[verifier::exec_allows_no_decreases_clause]
189 pub fn wake_all(&self) -> (r: usize) {
190 proof!{
191 use_type_invariant(self);
192 }
193
194 if self.is_empty() {
196 return 0;
197 }
198 let mut num_woken = 0;
199
200 loop
201 invariant
202 self.wf(),
203 {
204 let mut wakers = self.wakers.lock();
205 let Some(waker) = wakers.pop_front() else {
206 wakers.drop();
207 break;
208 };
209 proof_decl!{
210 let tracked count_mirror = wakers.tracked_borrow_mut_resource();
211 }
212 atomic_with_ghost! {
213 self.num_wakers => fetch_sub(1);
214 update prev -> next;
215 ghost count_auth => {
216 count_auth.agree(&*count_mirror);
217 assert(prev == count_mirror@);
218 assert(prev > 0);
219 count_auth.update(count_mirror, next);
220 }
221 };
222 wakers.drop();
225
226 if waker.wake_up() {
227 assume(num_woken < usize::MAX);
228 num_woken += 1;
229 }
230 }
231
232 num_woken
233 }
234
235 fn is_empty(&self) -> bool {
236 proof! {
237 use_type_invariant(self);
238 }
239 self.num_wakers.load() == 0
240 }
241
242 #[doc(hidden)]
244 pub fn enqueue(&self, waker: Arc<Waker>) {
245 proof!{
246 use_type_invariant(self);
247 }
248 let mut wakers = self.wakers.lock();
249 wakers.push_back(waker);
250 proof_decl!{
251 let tracked count_mirror = wakers.tracked_borrow_mut_resource();
252 }
253 atomic_with_ghost! {
254 self.num_wakers => fetch_add(1);
255 update prev -> next;
256 ghost count_auth => {
257 count_auth.agree(&*count_mirror);
258 assert(prev == count_mirror@);
259 assume(prev < u32::MAX);
260 count_auth.update(count_mirror, next);
261 }
262 };
263 wakers.drop();
264 }
265}
266
267impl Default for WaitQueue {
268 fn default() -> Self {
269 Self::new()
270 }
271}
272
273pub struct Waiter {
279 waker: Arc<Waker>,
280}
281
282impl !Send for Waiter {
283
284}
285
286impl !Sync for Waiter {
287
288}
289
290impl Waiter {
291 pub closed spec fn rel_waker(self, waker: Arc<Waker>) -> bool {
293 self.waker == waker
294 }
295}
296
297struct_with_invariants! {
298pub struct Waker {
303 has_woken: AtomicBool<_, (), _>, task: Arc<Task>,
305}
306
307closed spec fn wf(self) -> bool {
308 invariant on has_woken is (v: bool, g: ()) {
309 true
310 }
311}
312}
313
314impl Waker {
315 #[verifier::type_invariant]
316 pub closed spec fn type_inv(self) -> bool {
317 self.wf()
318 }
319}
320
321#[verus_verify]
322impl Waiter {
323 #[verus_spec(ret =>
325 ensures
326 ret.0.rel_waker(ret.1),
327 )]
328 pub fn new_pair() -> (Self, Arc<Waker>) {
329 proof_decl! {
330 let ghost waker_id: int = arbitrary();
331 }
332 let waker = Arc::new(
333 Waker {
334 has_woken: AtomicBool::new(Ghost(()), false, Tracked(())),
335 task: Arc::new(Task { }),
337 },
338 );
339 let waiter = Self { waker: waker.clone() };
340 (waiter, waker)
341 }
342
343 #[track_caller]
350 pub fn wait(&self) {
351 self.waker.do_wait();
352 }
353
354 #[verus_spec(ret =>
360 requires
361 cond.requires(()),
362 cancel_cond.requires(()),
363 ensures
364 match ret {
365 Ok(res) => cond.ensures((),Some(res)),
366 Err(e) => cancel_cond.ensures((), Err(e)),
367 },
368 )]
369 #[track_caller]
370 #[verifier::exec_allows_no_decreases_clause]
371 pub fn wait_until_or_cancelled<F, R, FCancel, E>(
372 &self,
373 mut cond: F,
374 cancel_cond: FCancel,
375 ) -> core::result::Result<R, E> where
376 F: FnMut() -> Option<R>,
377 FCancel: Fn() -> core::result::Result<(), E>,
378 {
379 let mut cond = cond;
380 #[verus_spec(invariant
381 cond.requires(()),
382 cancel_cond.requires(()),
383 )]
384 loop {
385 if let Some(res) = cond() {
386 assert(cond.ensures((), Some(res))) by {
387 admit();
388 }; proof! { admit(); } return Ok(res);
391 };
392 if let Err(e) = cancel_cond() {
393 self.waker.close();
395 proof! { admit(); } return cond().ok_or(e);
397 }
398 self.wait();
399 }
400 }
401
402 #[verus_spec(ret =>
404 ensures
405 self.rel_waker(ret),
406 )]
407 pub fn waker(&self) -> Arc<Waker> {
408 self.waker.clone()
409 }
410
411 pub fn task(&self) -> &Arc<Task> {
413 &self.waker.task
414 }
415}
416
417impl Waiter {
430 pub fn drop(self) {
432 self.waker.close();
435 }
436}
437
438impl Waker {
439 #[verifier::external_body]
449 pub fn wake_up(&self) -> bool {
450 unimplemented!()
457 }
458
459 #[track_caller]
460 #[verifier::external_body]
461 fn do_wait(&self) {
462 unimplemented!()
466 }
467
468 fn close(&self) {
469 proof!{ use_type_invariant(self);}
473 let _ =
474 atomic_with_ghost!{
475 self.has_woken => swap(true);
476 update prev -> next;
477 ghost g => {}
478 };
479 }
480}
481
482} #[cfg(ktest)]
484mod test {
485 use super::*;
486 use crate::{prelude::*, task::TaskOptions};
487
488 fn queue_wake<F>(wake: F)
489 where
490 F: Fn(&WaitQueue) + Sync + Send + 'static,
491 {
492 let queue = Arc::new(WaitQueue::new());
493 let queue_cloned = queue.clone();
494
495 let cond = Arc::new(AtomicBool::new(false));
496 let cond_cloned = cond.clone();
497
498 TaskOptions::new(move || {
499 Task::yield_now();
500
501 cond_cloned.store(true, Ordering::Relaxed);
502 wake(&queue_cloned);
503 })
504 .data(())
505 .spawn()
506 .unwrap();
507
508 queue.wait_until(|| cond.load(Ordering::Relaxed).then_some(()));
509
510 assert!(cond.load(Ordering::Relaxed));
511 }
512
513 #[ktest]
514 fn queue_wake_one() {
515 queue_wake(|queue| {
516 queue.wake_one();
517 });
518 }
519
520 #[ktest]
521 fn queue_wake_all() {
522 queue_wake(|queue| {
523 queue.wake_all();
524 });
525 }
526
527 #[ktest]
528 fn waiter_wake_twice() {
529 let (_waiter, waker) = Waiter::new_pair();
530
531 assert!(waker.wake_up());
532 assert!(!waker.wake_up());
533 }
534
535 #[ktest]
536 fn waiter_wake_drop() {
537 let (waiter, waker) = Waiter::new_pair();
538
539 drop(waiter);
540 assert!(!waker.wake_up());
541 }
542
543 #[ktest]
544 fn waiter_wake_async() {
545 let (waiter, waker) = Waiter::new_pair();
546
547 let cond = Arc::new(AtomicBool::new(false));
548 let cond_cloned = cond.clone();
549
550 TaskOptions::new(move || {
551 Task::yield_now();
552
553 cond_cloned.store(true, Ordering::Relaxed);
554 assert!(waker.wake_up());
555 })
556 .data(())
557 .spawn()
558 .unwrap();
559
560 waiter.wait();
561
562 assert!(cond.load(Ordering::Relaxed));
563 }
564
565 #[ktest]
566 fn waiter_wake_reorder() {
567 let (waiter, waker) = Waiter::new_pair();
568
569 let cond = Arc::new(AtomicBool::new(false));
570 let cond_cloned = cond.clone();
571
572 let (waiter2, waker2) = Waiter::new_pair();
573
574 let cond2 = Arc::new(AtomicBool::new(false));
575 let cond2_cloned = cond2.clone();
576
577 TaskOptions::new(move || {
578 Task::yield_now();
579
580 cond2_cloned.store(true, Ordering::Relaxed);
581 assert!(waker2.wake_up());
582
583 Task::yield_now();
584
585 cond_cloned.store(true, Ordering::Relaxed);
586 assert!(waker.wake_up());
587 })
588 .data(())
589 .spawn()
590 .unwrap();
591
592 waiter.wait();
593 assert!(cond.load(Ordering::Relaxed));
594
595 waiter2.wait();
596 assert!(cond2.load(Ordering::Relaxed));
597 }
598}