1use vstd::atomic_ghost::*;
3use vstd::cell::{self, CellId, pcell::*};
4use vstd::prelude::*;
5use vstd::resource::Loc;
6#[cfg(feature = "irc11")]
7use vstd::thread_view::Objective;
8use vstd_extra::resource::ghost_resource::{count_auth::*, count_ghost::*, csum::*, excl::*};
9use vstd_extra::sum::*;
10
11use core::{
12 cell::UnsafeCell,
13 ops::{Deref, DerefMut},
14 sync::atomic::{
15 Ordering::{AcqRel, Acquire, Relaxed, Release},
17 },
18};
19
20use super::WaitQueue;
21
22verus! {
23
24type NoPerm<T> = EmptyCount<PointsTo<T>>;
25
26type HalfPerm<T> = Count<PointsTo<T>>;
27
28type ReadPerm<T> = (HalfPerm<T>, OneLeftKnowledge<HalfPerm<T>, NoPerm<T>, 3>);
29
30tracked struct RwPerms<T> {
31 core_token: SumResource<HalfPerm<T>, NoPerm<T>, 3>,
32 read_retract_token: TokenResource<MAX_READER_MASK>,
33 upread_retract_token: Option<UniqueToken>,
34 upreader_guard_token: Option<OneLeftOwner<HalfPerm<T>, NoPerm<T>, 3>>,
35 read_guard_token: CountResource<ReadPerm<T>, MAX_READER>,
36}
37
38#[cfg(feature = "irc11")]
39unsafe impl<T> Objective for RwPerms<T> {
40
41}
42
43ghost struct RwId {
44 core_token_id: Loc,
45 frac_id: Loc,
46 read_retract_token_id: Loc,
47 upread_retract_token_id: Loc,
48 read_guard_token_id: Loc,
49}
50
51#[verifier::reject_recursive_types(T)]
52struct_with_invariants! {
53pub struct RwMutex<T > {
127 lock: AtomicUsize<_, RwPerms<T>, _>,
133 queue: WaitQueue,
135 val: PCell<T>,
137 ghost_id: Ghost<RwId>,
138}
139
140closed spec fn wf(self) -> bool {
141 invariant on lock with (val, ghost_id) is (v: usize, g: RwPerms<T>) {
142 let has_writer_bit: bool = (v & WRITER) != 0;
143 let has_upgrade_bit: bool = (v & UPGRADEABLE_READER) != 0;
144 let has_max_reader_bit: bool = (v & MAX_READER) != 0;
145 let total_reader_bits: int = (v & MAX_READER_MASK) as int;
146 let reader_bits: int = if has_max_reader_bit {
147 MAX_READER as int
148 } else {
149 (v & READER_MASK) as int
150 };
151
152 let active_writer: bool = g.core_token.is_right();
153 let active_upgrade_guard: bool = !active_writer && g.upreader_guard_token is None;
154 let active_read_guards: int = if g.read_guard_token.is_resource_vacant() {
155 0
156 } else {
157 MAX_READER - g.read_guard_token.frac()
158 };
159 let pending_failed_upread_attempt: bool = g.upread_retract_token is None;
160 let failed_reader_attempts: int = MAX_READER_MASK - g.read_retract_token.frac();
161
162 &&& if g.core_token.is_left() {
163 let resource = g.read_guard_token.resource();
164 let read_half_cell_perm = resource.0;
165 let mode_knowledge = resource.1;
166 &&& !g.read_guard_token.is_resource_vacant()
167 &&& mode_knowledge.id() == ghost_id@.core_token_id
168 &&& read_half_cell_perm.id() == ghost_id@.frac_id
169 &&& read_half_cell_perm.resource().id() == val.id()
170 &&& read_half_cell_perm.frac() == 1
171 } else {
172 &&& g.upreader_guard_token is None
173 &&& g.read_guard_token.is_resource_vacant()
174 }
175 &&& has_upgrade_bit <==> (active_upgrade_guard || pending_failed_upread_attempt)
176 &&& !(active_upgrade_guard && pending_failed_upread_attempt)
177 &&& total_reader_bits == active_read_guards + failed_reader_attempts
178 &&& active_writer <==> has_writer_bit
179 &&& 0 <= active_read_guards <= reader_bits <= total_reader_bits
180 &&& !(active_writer && (active_read_guards + if active_upgrade_guard { 1int } else { 0 }) > 0)
181 &&& g.core_token.id() == ghost_id@.core_token_id
182 &&& g.core_token.wf()
183 &&& g.core_token.is_left() ==> {
184 &&& !g.core_token.is_resource_owner()
185 &&& g.core_token.frac() == 1
186 }
187 &&& g.core_token.is_right() ==> {
188 let empty = g.core_token.resource_right();
189 &&& empty.id() == ghost_id@.frac_id
190 &&& g.core_token.frac() == 2
191 &&& g.core_token.has_resource()
192 }
193 &&& g.read_retract_token.wf()
194 &&& g.read_retract_token.id() == ghost_id@.read_retract_token_id
195 &&& g.upread_retract_token is Some ==> {
196 let token = g.upread_retract_token->0;
197 &&& token.wf()
198 &&& token.id() == ghost_id@.upread_retract_token_id
199 }
200 &&& g.upreader_guard_token is Some ==> {
201 let token = g.upreader_guard_token->0;
202 wf_upgradeable_guard_token(ghost_id@.core_token_id, ghost_id@.frac_id, val.id(), token)
203 }
204 &&& g.read_guard_token.wf()
205 &&& g.read_guard_token.id() == ghost_id@.read_guard_token_id
206 }
207}
208}
209
210const READER: usize = 1;
211
212const WRITER: usize = 1 << (usize::BITS - 1);
213
214const UPGRADEABLE_READER: usize = 1 << (usize::BITS - 2);
215
216const BEING_UPGRADED: usize = 1 << (usize::BITS - 3);
217
218const MAX_READER: usize = 1 << (usize::BITS - 4);
222
223const READER_MASK: usize = usize::MAX >> 4;
224
225const MAX_READER_MASK: usize = usize::MAX >> 3;
226
227pub closed spec fn no_max_reader_overflow(v: usize) -> bool {
228 v & MAX_READER_MASK < MAX_READER_MASK
229}
230
231impl<T> RwMutex<T> {
232 pub closed spec fn cell_id(self) -> cell::CellId {
233 self.val.id()
234 }
235
236 pub closed spec fn core_token_id(self) -> Loc {
237 self.ghost_id@.core_token_id
238 }
239
240 pub closed spec fn frac_id(self) -> Loc {
241 self.ghost_id@.frac_id
242 }
243
244 pub closed spec fn upread_retract_token_id(self) -> Loc {
245 self.ghost_id@.upread_retract_token_id
246 }
247
248 pub closed spec fn read_guard_token_id(self) -> Loc {
249 self.ghost_id@.read_guard_token_id
250 }
251
252 #[verifier::type_invariant]
253 pub closed spec fn type_inv(self) -> bool {
254 self.wf()
255 }
256}
257
258closed spec fn wf_upgradeable_guard_token<T>(
259 core_token_id: Loc,
260 frac_id: Loc,
261 cell_id: CellId,
262 token: OneLeftOwner<HalfPerm<T>, NoPerm<T>, 3>,
263) -> bool {
264 let half_cell_perm = token.resource();
265 &&& token.id() == core_token_id
266 &&& half_cell_perm.id() == frac_id
267 &&& half_cell_perm.resource().id() == cell_id
268 &&& token.has_resource()
269 &&& half_cell_perm.frac() == 1
270 &&& half_cell_perm.has_authority()
271 &&& token.wf()
272}
273
274impl<T> RwMutex<T> {
275 pub const fn new(val: T) -> Self {
277 let (val, Tracked(perm)) = PCell::new(val);
278
279 proof {
280 lemma_consts_properties();
281 }
282 let tracked mut frac_perm = Count::<PointsTo<T>>::alloc(perm);
283 let tracked read_half_cell_perm = frac_perm.split(1int);
284 let ghost frac_id = frac_perm.id();
285 let tracked mut core_token = SumResource::alloc_left(frac_perm);
286 let tracked read_retract_token = TokenResource::<MAX_READER_MASK>::alloc(());
287 let tracked upread_retract_token = UniqueToken::alloc(());
288 let tracked upreader_guard_token = core_token.split_one_left_owner();
289 let tracked left_token = core_token.split_one_left_knowledge();
290 let tracked read_guard_token = CountResource::<ReadPerm<T>, MAX_READER>::alloc(
291 (read_half_cell_perm, left_token),
292 );
293 let ghost ghost_id = RwId {
294 frac_id,
295 core_token_id: core_token.id(),
296 upread_retract_token_id: upread_retract_token.id(),
297 read_retract_token_id: read_retract_token.id(),
298 read_guard_token_id: read_guard_token.id(),
299 };
300 let tracked perms = RwPerms {
301 core_token,
302 read_retract_token,
303 upread_retract_token: Some(upread_retract_token),
304 upreader_guard_token: Some(upreader_guard_token),
305 read_guard_token,
306 };
307
308 Self {
309 val,
311 lock: AtomicUsize::new(Ghost((val, Ghost(ghost_id))), 0, Tracked(perms)),
312 queue: WaitQueue::new(),
313 ghost_id: Ghost(ghost_id),
314 }
315 }
316}
317
318#[verus_verify]
319impl<T > RwMutex<T> {
320 #[track_caller]
327 pub fn read(&self) -> RwMutexReadGuard<'_, T> {
328 self.queue.wait_until(|| self.try_read())
329 }
330
331 #[track_caller]
338 pub fn write(&self) -> RwMutexWriteGuard<'_, T> {
339 self.queue.wait_until(|| self.try_write())
340 }
341
342 #[track_caller]
353 pub fn upread(&self) -> RwMutexUpgradeableGuard<'_, T> {
354 self.queue.wait_until(|| self.try_upread())
355 }
356
357 #[verus_spec]
361 pub fn try_read(&self) -> Option<RwMutexReadGuard<'_, T>> {
362 proof_decl! {
363 let tracked mut read_token: Option<Count<ReadPerm<T>, MAX_READER>> = None;
364 let tracked mut retract_read_token: Option<Token<MAX_READER_MASK>> = None;
365 }
366 proof! {
367 use_type_invariant(self);
368 lemma_consts_properties();
369 }
370
371 let lock =
372 atomic_with_ghost!(
373 self.lock => fetch_add(READER);
374 update prev -> next;
375 ghost g => {
376 let prev_usize = prev as usize;
377 let next_usize = next as usize;
378 assume(no_max_reader_overflow(prev_usize));
379 lemma_consts_properties_value(prev_usize);
380 lemma_consts_properties_prev_next(prev_usize, next_usize);
381 if prev_usize & (WRITER | BEING_UPGRADED | MAX_READER) == 0 {
382 read_token = Some(g.read_guard_token.split_one());
383 } else {
384 retract_read_token = Some(g.read_retract_token.split_one());
385 }
386 }
387 );
388
389 if lock & (WRITER | BEING_UPGRADED | MAX_READER) == 0 {
390 Some(
391 RwMutexReadGuard {
392 inner: self,
393 tracked_token: Tracked(read_token.tracked_unwrap()),
394 },
395 )
396 } else {
397 atomic_with_ghost!(
398 self.lock => fetch_sub(READER);
399 update prev -> next;
400 ghost g => {
401 let prev_usize = prev as usize;
402 let next_usize = next as usize;
403 lemma_consts_properties_value(next_usize);
404 lemma_consts_properties_prev_next(prev_usize, next_usize);
405 g.read_retract_token.combine(retract_read_token.tracked_unwrap());
406 }
407 );
408 None
409 }
410 }
411
412 pub fn try_write(&self) -> Option<RwMutexWriteGuard<'_, T>> {
416 proof_decl! {
417 let tracked mut guard_perm: Option<PointsTo<T>> = None;
418 let tracked mut guard_token: Option<OneRightKnowledge<HalfPerm<T>, NoPerm<T>, 3>> = None;
419 }
420 proof! {
421 use_type_invariant(self);
422 lemma_consts_properties();
423 }
424
425 if atomic_with_ghost!(
426 self.lock => compare_exchange(0, WRITER);
427 update prev -> next;
428 returning res;
429 ghost g => {
430 let prev_usize = prev as usize;
431 let next_usize = next as usize;
432 if res is Ok {
433 let tracked read_resource = g.read_guard_token.take_resource();
434 let tracked (read_half_cell_perm, left_token) = read_resource;
435 g.core_token.join_one_left_knowledge(left_token);
436 let tracked upreader_guard_token = g.upreader_guard_token.tracked_take();
437 g.core_token.join_one_left_owner(upreader_guard_token);
438 let tracked mut pointsto = g.core_token.take_resource_left();
439 pointsto.combine(read_half_cell_perm);
440 let tracked (pointsto, empty) = pointsto.take_resource();
441 guard_perm = Some(pointsto);
442 g.core_token.change_to_right(empty);
443 guard_token = Some(g.core_token.split_one_right_knowledge());
444 } else {
445 lemma_consts_properties_prev_next(prev_usize, next_usize);
446 }
447 }
448 ).is_ok() {
449 Some(
450 RwMutexWriteGuard {
451 inner: self,
452 tracked_perm: Tracked(guard_perm.tracked_unwrap()),
453 tracked_token: Tracked(guard_token.tracked_unwrap()),
454 },
455 )
456 } else {
457 None
458 }
459 }
460
461 pub fn try_upread(&self) -> Option<RwMutexUpgradeableGuard<'_, T>> {
465 proof_decl! {
466 let tracked mut upgrade_guard_token: Option<OneLeftOwner<HalfPerm<T>, NoPerm<T>, 3>> = None;
467 let tracked mut retract_upgrade_token: Option<UniqueToken> = None;
468 }
469 proof! {
470 use_type_invariant(self);
471 lemma_consts_properties();
472 }
473
474 let lock =
475 atomic_with_ghost!(
476 self.lock => fetch_or(UPGRADEABLE_READER);
477 update prev -> next;
478 ghost g => {
479 lemma_consts_properties_value(prev);
480 lemma_consts_properties_prev_next(prev, next);
481 if prev & (WRITER | UPGRADEABLE_READER) == 0 {
482 upgrade_guard_token = Some(g.upreader_guard_token.tracked_take());
483 } else if prev & (WRITER | UPGRADEABLE_READER) == WRITER {
484 retract_upgrade_token = Some(g.upread_retract_token.tracked_take());
485 }
486 }
487 )
488 & (WRITER | UPGRADEABLE_READER);
489
490 if lock == 0 {
491 return Some(
492 RwMutexUpgradeableGuard {
493 inner: self,
494 tracked_token: Tracked(upgrade_guard_token.tracked_unwrap()),
495 },
496 );
497 } else if lock == WRITER {
498 atomic_with_ghost!(
499 self.lock => fetch_sub(UPGRADEABLE_READER);
500 update prev -> next;
501 ghost g => {
502 let prev_usize = prev as usize;
503 let next_usize = next as usize;
504 lemma_consts_properties_value(prev_usize);
505 lemma_consts_properties_prev_next(prev_usize, next_usize);
506 if g.upread_retract_token is Some {
507 let tracked mut token = retract_upgrade_token.tracked_unwrap();
508 token.validate_with_other(g.upread_retract_token.tracked_borrow());
509 } else {
510 g.upread_retract_token = retract_upgrade_token;
511 }
512 }
513 );
514 }
515 None
516 }}
525
526#[verifier::external]
535unsafe impl<T: Send> Send for RwMutex<T> {
536
537}
538
539#[verifier::external]
540unsafe impl<T: Send + Sync> Sync for RwMutex<T> {
541
542}
543
544impl<T > !Send for RwMutexWriteGuard<'_, T> {
545
546}
547
548#[verifier::external]
549unsafe impl<T: Sync> Sync for RwMutexWriteGuard<'_, T> {
550
551}
552
553impl<T > !Send for RwMutexReadGuard<'_, T> {
554
555}
556
557#[verifier::external]
558unsafe impl<T: Sync> Sync for RwMutexReadGuard<'_, T> {
559
560}
561
562impl<T > !Send for RwMutexUpgradeableGuard<'_, T> {
563
564}
565
566#[verifier::external]
567unsafe impl<T: Sync> Sync for RwMutexUpgradeableGuard<'_, T> {
568
569}
570
571#[verifier::reject_recursive_types(T)]
573#[clippy::has_significant_drop]
574#[must_use]
575pub struct RwMutexReadGuard<'a, T > {
576 inner: &'a RwMutex<T>,
577 tracked_token: Tracked<Count<ReadPerm<T>, MAX_READER>>,
578}
579
580impl<'a, T> RwMutexReadGuard<'a, T> {
581 #[verifier::type_invariant]
582 pub closed spec fn type_inv(self) -> bool {
583 let resource = self.tracked_token@.resource();
584 let read_half_cell_perm = resource.0;
585 let mode_knowledge = resource.1;
586 &&& self.inner.core_token_id() == mode_knowledge.id()
587 &&& self.inner.frac_id() == read_half_cell_perm.id()
588 &&& self.inner.cell_id() == read_half_cell_perm.resource().id()
589 &&& self.tracked_token@.id() == self.inner.read_guard_token_id()
590 &&& read_half_cell_perm.frac() == 1
591 &&& self.tracked_token@.frac() == 1
592 }
593
594 pub closed spec fn value(self) -> T {
595 *self.tracked_token@.resource().0.resource().value()
596 }
597
598 pub open spec fn view(self) -> T {
599 self.value()
600 }
601}
602
603impl<T > Deref for RwMutexReadGuard<'_, T> {
604 type Target = T;
605
606 #[verus_spec(returns self.view())]
607 fn deref(&self) -> &T {
608 proof! {
609 use_type_invariant(self);
610 }
611 self.inner.val.borrow(
613 Tracked(self.tracked_token.borrow().tracked_borrow().0.tracked_borrow()),
614 )
615 }
616}
617
618impl<T > RwMutexReadGuard<'_, T> {
619 fn drop(self) {
620 proof! {
622 use_type_invariant(&self);
623 use_type_invariant(self.inner);
624 lemma_consts_properties();
625 }
626 proof_decl! {
627 let tracked token = self.tracked_token.get();
628 }
629 if atomic_with_ghost!(
630 self.inner.lock => fetch_sub(READER);
631 update prev -> next;
632 ghost g => {
633 let prev_usize = prev as usize;
634 let next_usize = next as usize;
635 assume(no_max_reader_overflow(prev_usize));
636 lemma_consts_properties_value(next_usize);
637 lemma_consts_properties_prev_next(prev_usize, next_usize);
638 g.core_token.validate_with_one_left_knowledge(&token.tracked_borrow().1);
639 g.read_guard_token.combine(token);
640 }
641 )
642 == READER {
643 self.inner.queue.wake_one();
644 }
645 }
646}
647
648#[clippy::has_significant_drop]
650#[must_use]
651#[verifier::reject_recursive_types(T)]
652pub struct RwMutexWriteGuard<'a, T > {
653 inner: &'a RwMutex<T>,
654 tracked_perm: Tracked<PointsTo<T>>,
655 tracked_token: Tracked<OneRightKnowledge<HalfPerm<T>, NoPerm<T>, 3>>,
656}
657
658impl<'a, T> RwMutexWriteGuard<'a, T> {
659 #[verifier::type_invariant]
660 spec fn type_inv(self) -> bool {
661 &&& self.inner.cell_id() == self.tracked_perm@.id()
662 &&& self.inner.core_token_id() == self.tracked_token@.id()
663 }
664
665 pub closed spec fn value(self) -> T {
666 *self.tracked_perm@.value()
667 }
668
669 pub open spec fn view(self) -> T {
670 self.value()
671 }
672}
673
674impl<T > Deref for RwMutexWriteGuard<'_, T> {
675 type Target = T;
676
677 #[verus_spec(returns self.view())]
678 fn deref(&self) -> &T {
679 proof! {
680 use_type_invariant(self);
681 }
682 self.inner.val.borrow(Tracked(self.tracked_perm.borrow()))
684 }
685}
686
687impl<'a, T > RwMutexWriteGuard<'a, T> {
688 #[verifier::exec_allows_no_decreases_clause]
692 pub fn downgrade(self) -> RwMutexUpgradeableGuard<'a, T> {
693 let mut this = self;
694 loop {
695 this =
696 match this.try_downgrade() {
697 Ok(guard) => return guard,
698 Err(e) => e,
699 };
700 }
701 }
702
703 fn try_downgrade(self) -> Result<RwMutexUpgradeableGuard<'a, T>, Self> {
706 proof! {
707 use_type_invariant(&self);
708 use_type_invariant(self.inner);
709 lemma_consts_properties();
710 }
711 proof_decl! {
712 let tracked perm = self.tracked_perm.get();
713 let tracked token = self.tracked_token.get();
714 let tracked mut upgrade_guard_token: Option<OneLeftOwner<HalfPerm<T>, NoPerm<T>, 3>> = None;
715 let tracked mut err_perm: Option<PointsTo<T>> = None;
716 let tracked mut err_write_guard_token: Option<OneRightKnowledge<HalfPerm<T>, NoPerm<T>, 3>> = None;
717 }
718 let inner = self.inner;
719 let res =
720 atomic_with_ghost!(
721 self.inner.lock => compare_exchange(WRITER, UPGRADEABLE_READER);
722 update prev -> next;
723 returning res;
724 ghost g => {
725 lemma_consts_properties_prev_next(prev, next);
726 if res is Ok {
727 g.core_token.validate_with_one_right_knowledge(&token);
728 g.core_token.join_one_right_knowledge(token);
729 let tracked empty = g.core_token.take_resource_right();
730 let tracked mut full = empty.put_resource(perm);
731 let tracked read_half_cell_perm = full.split(1int);
732 g.core_token.change_to_left(full);
733 upgrade_guard_token = Some(g.core_token.split_one_left_owner());
734 let tracked left_token = g.core_token.split_one_left_knowledge();
735 g.read_guard_token.put_resource((read_half_cell_perm, left_token));
736 } else {
737 err_perm = Some(perm);
738 err_write_guard_token = Some(token);
739 }
740 }
741 );
742
743 if res.is_ok() {
744 atomic_with_ghost! {
746 self.inner.lock => fetch_and(!WRITER);
747 update prev -> next;
748 ghost g => {
749 let prev_usize = prev as usize;
750 let next_usize = next as usize;
751 let tracked mut guard_token = upgrade_guard_token.tracked_unwrap();
752 g.core_token.validate_with_one_left_owner(&guard_token);
753 if g.upreader_guard_token is Some {
754 guard_token.validate_with_one_left_owner(
755 g.upreader_guard_token.tracked_borrow(),
756 );
757 assert(false);
758 }
759 upgrade_guard_token = Some(guard_token);
760 lemma_consts_properties_value(prev_usize);
761 lemma_consts_properties_prev_next(prev_usize, next_usize);
762 lemma_consts_properties_value(next_usize);
763 }
764 };
765 self.inner.queue.wake_all();
766 Ok(
767 RwMutexUpgradeableGuard {
768 inner,
769 tracked_token: Tracked(upgrade_guard_token.tracked_unwrap()),
770 },
771 )
772 } else {
773 Err(
774 RwMutexWriteGuard {
775 inner,
776 tracked_perm: Tracked(err_perm.tracked_unwrap()),
777 tracked_token: Tracked(err_write_guard_token.tracked_unwrap()),
778 },
779 )
780 }
781 }
782
783 pub fn drop(self) {
784 proof! {
785 use_type_invariant(&self);
786 use_type_invariant(self.inner);
787 lemma_consts_properties();
788 }
789 proof_decl! {
790 let tracked perm = self.tracked_perm.get();
791 let tracked token = self.tracked_token.get();
792 }
793 atomic_with_ghost! {
794 self.inner.lock => fetch_and(!WRITER);
795 update prev -> next;
796 ghost g => {
797 let prev_usize = prev as usize;
798 let next_usize = next as usize;
799 lemma_consts_properties_prev_next(prev_usize, next_usize);
800 lemma_consts_properties_value(next_usize);
801 g.core_token.validate_with_one_right_knowledge(&token);
802 g.core_token.join_one_right_knowledge(token);
803 let tracked empty = g.core_token.take_resource_right();
804 let tracked mut full = empty.put_resource(perm);
805 let tracked read_half_cell_perm = full.split(1int);
806 g.core_token.change_to_left(full);
807 let tracked upreader_guard_token = g.core_token.split_one_left_owner();
808 g.upreader_guard_token = Some(upreader_guard_token);
809 let tracked left_token = g.core_token.split_one_left_knowledge();
810 g.read_guard_token.put_resource((read_half_cell_perm, left_token));
811 }
812 };
813 self.inner.queue.wake_all();
818 }
819}
820
821#[verus_verify]
822impl<T > DerefMut for RwMutexWriteGuard<'_, T> {
823 #[verus_spec(ret =>
824 ensures
825 final(self).view() == *final(ret),
826 old(self).view() == *ret,
827 )]
828 fn deref_mut(&mut self) -> (ret: &mut Self::Target) {
829 proof! {
830 use_type_invariant(&*self);
831 }
832 self.inner.val.borrow_mut(Tracked(&mut *self.tracked_perm))
834 }
835}
836
837#[verifier::reject_recursive_types(T)]
840pub struct RwMutexUpgradeableGuard<'a, T > {
841 inner: &'a RwMutex<T>,
842 tracked_token: Tracked<OneLeftOwner<HalfPerm<T>, NoPerm<T>, 3>>,
843}
844
845impl<'a, T > RwMutexUpgradeableGuard<'a, T> {
846 #[verifier::type_invariant]
847 pub closed spec fn type_inv(self) -> bool {
848 wf_upgradeable_guard_token(
849 self.inner.core_token_id(),
850 self.inner.frac_id(),
851 self.inner.cell_id(),
852 self.tracked_token@,
853 )
854 }
855
856 pub closed spec fn value(self) -> T {
857 *self.tracked_token@.resource().resource().value()
858 }
859
860 pub open spec fn view(self) -> T {
861 self.value()
862 }
863}
864
865#[verus_verify]
866impl<'a, T> RwMutexUpgradeableGuard<'a, T> {
867 #[verifier::exec_allows_no_decreases_clause]
877 pub fn upgrade(self) -> RwMutexWriteGuard<'a, T> {
878 let mut this = self;
879 proof! {
880 use_type_invariant(&this);
881 use_type_invariant(&this.inner);
882 lemma_consts_properties();
883 }
884 atomic_with_ghost!(
885 this.inner.lock => fetch_or(BEING_UPGRADED);
886 update prev -> next;
887 ghost g => {
888 lemma_consts_properties_prev_next(prev, next);
889 }
890 );
891 loop {
892 this =
893 match this.try_upgrade() {
894 Ok(guard) => return guard,
895 Err(e) => e,
896 };
897 }
898 }
899
900 #[verus_spec]
908 fn try_upgrade(self) -> Result<RwMutexWriteGuard<'a, T>, Self> {
909 proof! {
910 use_type_invariant(&self);
911 use_type_invariant(self.inner);
912 lemma_consts_properties();
913 }
914 proof_decl! {
915 let tracked upread_guard_token = self.tracked_token.get();
916 let tracked mut write_perm: Option<PointsTo<T>> = None;
917 let tracked mut err_upread_guard_token: Option<OneLeftOwner<HalfPerm<T>, NoPerm<T>, 3>> = None;
918 let tracked mut retract_upgrade_token: Option<UniqueToken> = None;
919 let tracked mut write_guard_token: Option<OneRightKnowledge<HalfPerm<T>, NoPerm<T>, 3>> = None;
920 }
921
922 let res =
923 atomic_with_ghost!(
924 self.inner.lock => compare_exchange(UPGRADEABLE_READER | BEING_UPGRADED, WRITER | UPGRADEABLE_READER);
925 update prev -> next;
926 returning res;
927 ghost g => {
928 lemma_consts_properties_prev_next(prev, next);
929 if res is Ok {
930 g.core_token.validate_with_one_left_owner(&upread_guard_token);
931 if g.upreader_guard_token is Some {
932 upread_guard_token.validate_with_one_left_owner(g.upreader_guard_token.tracked_borrow());
933 }
934 g.core_token.join_one_left_owner(upread_guard_token);
935 let tracked read_resource = g.read_guard_token.take_resource();
936 let tracked (read_half_cell_perm, left_token) = read_resource;
937 g.core_token.join_one_left_knowledge(left_token);
938 let tracked mut pointsto = g.core_token.take_resource_left();
939 pointsto.combine(read_half_cell_perm);
940 let tracked (pointsto, empty) = pointsto.take_resource();
941 write_perm = Some(pointsto);
942 g.core_token.change_to_right(empty);
943 write_guard_token = Some(g.core_token.split_one_right_knowledge());
944 retract_upgrade_token = Some(g.upread_retract_token.tracked_take());
945 } else {
946 err_upread_guard_token = Some(upread_guard_token);
947 }
948 }
949 );
950
951 if res.is_ok() {
952 let inner = self.inner;
953 atomic_with_ghost!(
954 inner.lock => fetch_sub(UPGRADEABLE_READER);
955 update prev -> next;
956 ghost g => {
957 let prev_usize = prev as usize;
958 let next_usize = next as usize;
959 lemma_consts_properties_value(prev_usize);
960 lemma_consts_properties_prev_next(prev_usize, next_usize);
961 let tracked mut token = retract_upgrade_token.tracked_unwrap();
962 if g.upread_retract_token is Some {
963 token.validate_with_other(g.upread_retract_token.tracked_borrow());
964 }
965 g.upread_retract_token = Some(token);
966 }
967 );
968 Ok(
969 RwMutexWriteGuard {
970 inner,
971 tracked_perm: Tracked(write_perm.tracked_unwrap()),
972 tracked_token: Tracked(write_guard_token.tracked_unwrap()),
973 },
974 )
975 } else {
976 Err(
977 RwMutexUpgradeableGuard {
978 inner: self.inner,
979 tracked_token: Tracked(err_upread_guard_token.tracked_unwrap()),
980 },
981 )
982 }
983 }
984
985 #[verus_spec]
986 pub fn drop(self) {
987 proof! {
988 use_type_invariant(&self);
989 use_type_invariant(self.inner);
990 lemma_consts_properties();
991 }
992 proof_decl! {
993 let tracked guard_token = self.tracked_token.get();
994 }
995 let res =
996 atomic_with_ghost!(
997 self.inner.lock => fetch_sub(UPGRADEABLE_READER);
998 update prev -> next;
999 ghost g => {
1000 let prev_usize = prev as usize;
1001 let next_usize = next as usize;
1002 lemma_consts_properties_value(prev_usize);
1003 lemma_consts_properties_prev_next(prev_usize, next_usize);
1004 g.core_token.validate_with_one_left_owner(&guard_token);
1005 if g.upreader_guard_token is Some {
1006 guard_token.validate_with_one_left_owner(g.upreader_guard_token.tracked_borrow());
1007 assert(false);
1008 } else {
1009 g.upreader_guard_token = Some(guard_token);
1010 }
1011 }
1012 );
1013 if res == UPGRADEABLE_READER {
1014 self.inner.queue.wake_all();
1015 }
1016 }
1017}
1018
1019impl<T > Deref for RwMutexUpgradeableGuard<'_, T> {
1020 type Target = T;
1021
1022 #[verus_spec(returns self.view())]
1023 fn deref(&self) -> &T {
1024 proof! {
1025 use_type_invariant(self);
1026 }
1027 self.inner.val.borrow(
1029 Tracked(self.tracked_token.borrow().tracked_borrow().tracked_borrow()),
1030 )
1031 }
1032}
1033
1034#[verifier::bit_vector]
1035proof fn lemma_consts_properties()
1036 ensures
1037 0 & WRITER == 0,
1038 0 & UPGRADEABLE_READER == 0,
1039 0 & BEING_UPGRADED == 0,
1040 0 & READER_MASK == 0,
1041 0 & MAX_READER_MASK == 0,
1042 0 & MAX_READER == 0,
1043 0 & READER == 0,
1044 WRITER == 0x8000_0000_0000_0000,
1045 UPGRADEABLE_READER == 0x4000_0000_0000_0000,
1046 BEING_UPGRADED == 0x2000_0000_0000_0000,
1047 READER_MASK == 0x0FFF_FFFF_FFFF_FFFF,
1048 MAX_READER_MASK == 0x1FFF_FFFF_FFFF_FFFF,
1049 MAX_READER == 0x1000_0000_0000_0000,
1050 WRITER & WRITER == WRITER,
1051 WRITER & !WRITER == 0,
1052 WRITER & BEING_UPGRADED == 0,
1053 WRITER & READER_MASK == 0,
1054 WRITER & MAX_READER_MASK == 0,
1055 WRITER & MAX_READER == 0,
1056 WRITER & UPGRADEABLE_READER == 0,
1057 BEING_UPGRADED & WRITER == 0,
1058 BEING_UPGRADED & UPGRADEABLE_READER == 0,
1059 UPGRADEABLE_READER & BEING_UPGRADED == 0,
1060 UPGRADEABLE_READER & READER_MASK == 0,
1061 UPGRADEABLE_READER & MAX_READER_MASK == 0,
1062 UPGRADEABLE_READER & MAX_READER == 0,
1063 BEING_UPGRADED & READER_MASK == 0,
1064 BEING_UPGRADED & MAX_READER_MASK == 0,
1065 BEING_UPGRADED & MAX_READER == 0,
1066 (UPGRADEABLE_READER | BEING_UPGRADED) & WRITER == 0,
1067 (UPGRADEABLE_READER | BEING_UPGRADED) & UPGRADEABLE_READER == UPGRADEABLE_READER,
1068 (UPGRADEABLE_READER | BEING_UPGRADED) & BEING_UPGRADED == BEING_UPGRADED,
1069 (UPGRADEABLE_READER | BEING_UPGRADED) & READER_MASK == 0,
1070 (UPGRADEABLE_READER | BEING_UPGRADED) & MAX_READER_MASK == 0,
1071 (UPGRADEABLE_READER | BEING_UPGRADED) & MAX_READER == 0,
1072 (WRITER | UPGRADEABLE_READER) & WRITER == WRITER,
1073 (WRITER | UPGRADEABLE_READER) & UPGRADEABLE_READER == UPGRADEABLE_READER,
1074 (WRITER | UPGRADEABLE_READER) & BEING_UPGRADED == 0,
1075 (WRITER | UPGRADEABLE_READER) & READER_MASK == 0,
1076 (WRITER | UPGRADEABLE_READER) & MAX_READER_MASK == 0,
1077 (WRITER | UPGRADEABLE_READER) & MAX_READER == 0,
1078{
1079}
1080
1081#[verifier::bit_vector]
1082proof fn lemma_consts_properties_value(prev: usize)
1083 ensures
1084 no_max_reader_overflow(prev) ==> prev + READER <= usize::MAX,
1085 prev & (WRITER | BEING_UPGRADED | MAX_READER) == 0 ==> {
1086 &&& prev & WRITER == 0
1087 &&& prev & BEING_UPGRADED == 0
1088 &&& prev & MAX_READER == 0
1089 },
1090 prev & (WRITER | UPGRADEABLE_READER) == 0 ==> {
1091 &&& prev & WRITER == 0
1092 &&& prev & UPGRADEABLE_READER == 0
1093 },
1094 prev & MAX_READER == 0 ==> prev & READER_MASK == prev & MAX_READER_MASK,
1095 prev & MAX_READER != 0 ==> prev & MAX_READER_MASK >= MAX_READER,
1096 prev & (WRITER | UPGRADEABLE_READER) == WRITER ==> {
1097 &&& prev & UPGRADEABLE_READER == 0
1098 &&& prev & WRITER == WRITER
1099 },
1100 prev & UPGRADEABLE_READER != 0 ==> prev >= UPGRADEABLE_READER,
1101 prev & UPGRADEABLE_READER == 0 ==> {
1102 ||| prev & (WRITER | UPGRADEABLE_READER) == 0
1103 ||| prev & (WRITER | UPGRADEABLE_READER) == WRITER
1104 },
1105{
1106}
1107
1108#[verifier::bit_vector]
1109proof fn lemma_consts_properties_prev_next(prev: usize, next: usize)
1110 ensures
1111 prev & READER_MASK < MAX_READER,
1112 next == UPGRADEABLE_READER && prev == WRITER ==> {
1113 &&& next & WRITER == 0
1114 &&& next & UPGRADEABLE_READER == UPGRADEABLE_READER
1115 &&& next & READER_MASK == 0
1116 &&& next & MAX_READER_MASK == 0
1117 &&& next & MAX_READER == 0
1118 &&& next & BEING_UPGRADED == 0
1119 },
1120 next == prev | UPGRADEABLE_READER ==> {
1121 &&& next & UPGRADEABLE_READER != 0
1122 &&& next & WRITER == prev & WRITER
1123 &&& next & READER_MASK == prev & READER_MASK
1124 &&& next & MAX_READER_MASK == prev & MAX_READER_MASK
1125 &&& next & MAX_READER == prev & MAX_READER
1126 &&& next & BEING_UPGRADED == prev & BEING_UPGRADED
1127 },
1128 next == prev | BEING_UPGRADED ==> {
1129 &&& next & BEING_UPGRADED != 0
1130 &&& next & WRITER == prev & WRITER
1131 &&& next & UPGRADEABLE_READER == prev & UPGRADEABLE_READER
1132 &&& next & READER_MASK == prev & READER_MASK
1133 &&& next & MAX_READER_MASK == prev & MAX_READER_MASK
1134 &&& next & MAX_READER == prev & MAX_READER
1135 },
1136 next == prev - UPGRADEABLE_READER && prev & UPGRADEABLE_READER != 0 ==> {
1137 &&& next & UPGRADEABLE_READER == 0
1138 &&& next & WRITER == prev & WRITER
1139 &&& next & READER_MASK == prev & READER_MASK
1140 &&& next & MAX_READER_MASK == prev & MAX_READER_MASK
1141 &&& next & MAX_READER == prev & MAX_READER
1142 &&& next & BEING_UPGRADED == prev & BEING_UPGRADED
1143 },
1144 next == prev - READER && prev & READER_MASK != 0 ==> {
1145 &&& next & READER_MASK == (prev & READER_MASK) - READER
1146 &&& next & MAX_READER_MASK == (prev & MAX_READER_MASK) - READER
1147 &&& next & UPGRADEABLE_READER == prev & UPGRADEABLE_READER
1148 &&& next & WRITER == prev & WRITER
1149 &&& next & MAX_READER == prev & MAX_READER
1150 &&& next & BEING_UPGRADED == prev & BEING_UPGRADED
1151 },
1152 next == prev - READER && prev & MAX_READER_MASK != 0 ==> {
1153 &&& next & MAX_READER_MASK == (prev & MAX_READER_MASK) - READER
1154 &&& next & UPGRADEABLE_READER == prev & UPGRADEABLE_READER
1155 &&& next & WRITER == prev & WRITER
1156 &&& next & BEING_UPGRADED == prev & BEING_UPGRADED
1157 },
1158 next == prev + READER && no_max_reader_overflow(prev) ==> {
1159 &&& next & READER_MASK == if (prev & READER_MASK) + READER == MAX_READER {
1160 0
1161 } else {
1162 (prev & READER_MASK) + READER
1163 }
1164 &&& next & MAX_READER_MASK == (prev & MAX_READER_MASK) + READER
1165 &&& next & UPGRADEABLE_READER == prev & UPGRADEABLE_READER
1166 &&& next & WRITER == prev & WRITER
1167 &&& next & MAX_READER == if (prev & READER_MASK) + READER == MAX_READER {
1168 MAX_READER
1169 } else {
1170 prev & MAX_READER
1171 }
1172 &&& next & BEING_UPGRADED == prev & BEING_UPGRADED
1173 },
1174 next == prev & !WRITER ==> {
1175 &&& next & WRITER == 0
1176 &&& next & UPGRADEABLE_READER == prev & UPGRADEABLE_READER
1177 &&& next & READER_MASK == prev & READER_MASK
1178 &&& next & MAX_READER_MASK == prev & MAX_READER_MASK
1179 &&& next & MAX_READER == prev & MAX_READER
1180 &&& next & BEING_UPGRADED == prev & BEING_UPGRADED
1181 },
1182{
1183}
1184
1185}