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