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 let waker = Arc::new(
330 Waker {
331 has_woken: AtomicBool::new(Ghost(()), false, Tracked(())),
332 task: Arc::new(Task { }),
334 },
335 );
336 let waiter = Self { waker: waker.clone() };
337 (waiter, waker)
338 }
339
340 #[track_caller]
347 pub fn wait(&self) {
348 self.waker.do_wait();
349 }
350
351 #[verus_spec(ret =>
357 requires
358 cond.requires(()),
359 cancel_cond.requires(()),
360 ensures
361 match ret {
362 Ok(res) => cond.ensures((),Some(res)),
363 Err(e) => cancel_cond.ensures((), Err(e)),
364 },
365 )]
366 #[track_caller]
367 #[verifier::exec_allows_no_decreases_clause]
368 pub fn wait_until_or_cancelled<F, R, FCancel, E>(
369 &self,
370 mut cond: F,
371 cancel_cond: FCancel,
372 ) -> core::result::Result<R, E> where
373 F: FnMut() -> Option<R>,
374 FCancel: Fn() -> core::result::Result<(), E>,
375 {
376 let mut cond = cond;
377 #[verus_spec(invariant
378 cond.requires(()),
379 cancel_cond.requires(()),
380 )]
381 loop {
382 if let Some(res) = cond() {
383 assert(cond.ensures((), Some(res))) by {
384 admit();
385 }; proof! { admit(); } return Ok(res);
388 };
389 if let Err(e) = cancel_cond() {
390 self.waker.close();
392 proof! { admit(); } return cond().ok_or(e);
394 }
395 self.wait();
396 }
397 }
398
399 #[verus_spec(ret =>
401 ensures
402 self.rel_waker(ret),
403 )]
404 pub fn waker(&self) -> Arc<Waker> {
405 self.waker.clone()
406 }
407
408 pub fn task(&self) -> &Arc<Task> {
410 &self.waker.task
411 }
412}
413
414impl Waiter {
427 pub fn drop(self) {
429 self.waker.close();
432 }
433}
434
435impl Waker {
436 #[verifier::external_body]
446 pub fn wake_up(&self) -> bool {
447 unimplemented!()
454 }
455
456 #[track_caller]
457 #[verifier::external_body]
458 fn do_wait(&self) {
459 unimplemented!()
463 }
464
465 fn close(&self) {
466 proof!{ use_type_invariant(self);}
470 let _ =
471 atomic_with_ghost!{
472 self.has_woken => swap(true);
473 update prev -> next;
474 ghost g => {}
475 };
476 }
477}
478
479} #[cfg(ktest)]
481mod test {
482 use super::*;
483 use crate::{prelude::*, task::TaskOptions};
484
485 fn queue_wake<F>(wake: F)
486 where
487 F: Fn(&WaitQueue) + Sync + Send + 'static,
488 {
489 let queue = Arc::new(WaitQueue::new());
490 let queue_cloned = queue.clone();
491
492 let cond = Arc::new(AtomicBool::new(false));
493 let cond_cloned = cond.clone();
494
495 TaskOptions::new(move || {
496 Task::yield_now();
497
498 cond_cloned.store(true, Ordering::Relaxed);
499 wake(&queue_cloned);
500 })
501 .data(())
502 .spawn()
503 .unwrap();
504
505 queue.wait_until(|| cond.load(Ordering::Relaxed).then_some(()));
506
507 assert!(cond.load(Ordering::Relaxed));
508 }
509
510 #[ktest]
511 fn queue_wake_one() {
512 queue_wake(|queue| {
513 queue.wake_one();
514 });
515 }
516
517 #[ktest]
518 fn queue_wake_all() {
519 queue_wake(|queue| {
520 queue.wake_all();
521 });
522 }
523
524 #[ktest]
525 fn waiter_wake_twice() {
526 let (_waiter, waker) = Waiter::new_pair();
527
528 assert!(waker.wake_up());
529 assert!(!waker.wake_up());
530 }
531
532 #[ktest]
533 fn waiter_wake_drop() {
534 let (waiter, waker) = Waiter::new_pair();
535
536 drop(waiter);
537 assert!(!waker.wake_up());
538 }
539
540 #[ktest]
541 fn waiter_wake_async() {
542 let (waiter, waker) = Waiter::new_pair();
543
544 let cond = Arc::new(AtomicBool::new(false));
545 let cond_cloned = cond.clone();
546
547 TaskOptions::new(move || {
548 Task::yield_now();
549
550 cond_cloned.store(true, Ordering::Relaxed);
551 assert!(waker.wake_up());
552 })
553 .data(())
554 .spawn()
555 .unwrap();
556
557 waiter.wait();
558
559 assert!(cond.load(Ordering::Relaxed));
560 }
561
562 #[ktest]
563 fn waiter_wake_reorder() {
564 let (waiter, waker) = Waiter::new_pair();
565
566 let cond = Arc::new(AtomicBool::new(false));
567 let cond_cloned = cond.clone();
568
569 let (waiter2, waker2) = Waiter::new_pair();
570
571 let cond2 = Arc::new(AtomicBool::new(false));
572 let cond2_cloned = cond2.clone();
573
574 TaskOptions::new(move || {
575 Task::yield_now();
576
577 cond2_cloned.store(true, Ordering::Relaxed);
578 assert!(waker2.wake_up());
579
580 Task::yield_now();
581
582 cond_cloned.store(true, Ordering::Relaxed);
583 assert!(waker.wake_up());
584 })
585 .data(())
586 .spawn()
587 .unwrap();
588
589 waiter.wait();
590 assert!(cond.load(Ordering::Relaxed));
591
592 waiter2.wait();
593 assert!(cond2.load(Ordering::Relaxed));
594 }
595}