1use vstd::atomic_ghost::*;
3use vstd::cell::{self, CellId, pcell::*};
4use vstd::prelude::*;
5use vstd::resource::Loc;
6use vstd_extra::resource::ghost_resource::{count::*, csum::*, excl::*, tokens::*};
7use vstd_extra::sum::*;
8use vstd_extra::{prelude::*, resource};
9
10use alloc::sync::Arc;
11use core::char::MAX;
12use core::{
13 cell::UnsafeCell,
14 fmt,
15 marker::PhantomData,
16 ops::{Deref, DerefMut},
17 sync::atomic::{
18 Ordering::{AcqRel, Acquire, Relaxed, Release},
20 },
21};
22
23use super::{
24 PreemptDisabled,
25 guard::{GuardTransfer, SpinGuardian},
26};
27
28verus! {
29
30const MAX_READER_U64: u64 = MAX_READER as u64;
31
32spec const V_MAX_READ_RETRACT_FRACS_SPEC: u64 = (MAX_READER_MASK + 1) as u64;
33
34#[verifier::when_used_as_spec(V_MAX_READ_RETRACT_FRACS_SPEC)]
35exec const V_MAX_READ_RETRACT_FRACS: u64
36 ensures
37 V_MAX_READ_RETRACT_FRACS == V_MAX_READ_RETRACT_FRACS_SPEC,
38 V_MAX_READ_RETRACT_FRACS == MAX_READER_MASK + 1,
39 V_MAX_READ_RETRACT_FRACS < u64::MAX,
40{
41 assert(MAX_READER_MASK + 1 < u64::MAX) by (compute_only);
42 (MAX_READER_MASK + 1) as u64
43}
44
45type NoPerm<T> = EmptyCount<PointsTo<T>>;
47
48type HalfPerm<T> = Count<PointsTo<T>>;
50
51type ReadPerm<T> = (HalfPerm<T>, OneLeftKnowledge<HalfPerm<T>, NoPerm<T>, 3>);
53
54tracked struct RwPerms<T> {
55 core_token: SumResource<HalfPerm<T>, NoPerm<T>, 3>,
60 read_retract_token: TokenResource<V_MAX_READ_RETRACT_FRACS>,
66 upread_retract_token: Option<UniqueToken>,
68 upreader_guard_token: Option<OneLeftOwner<HalfPerm<T>, NoPerm<T>, 3>>,
70 read_guard_token: Sum<
73 CountResource<ReadPerm<T>, MAX_READER_U64>,
74 EmptyCount<ReadPerm<T>, MAX_READER_U64>,
75 >,
76}
77
78ghost struct RwId {
79 core_token_id: Loc,
80 frac_id: Loc,
81 read_retract_token_id: Loc,
82 upread_retract_token_id: Loc,
83 read_guard_token_id: Loc,
84}
85
86pub closed spec fn no_max_reader_overflow(v: usize) -> bool {
92 v & MAX_READER_MASK < MAX_READER_MASK
93}
94
95struct_with_invariants! {
96pub struct RwLock<T , Guard > {
175 guard: PhantomData<Guard>,
176 lock: AtomicUsize<_, RwPerms<T>,_>,
182 val: PCell<T>,
184 ghost_id: Ghost<RwId>,
185}
186
187closed spec fn wf(self) -> bool {
189 invariant on lock with (val, guard, ghost_id) is (v: usize, g: RwPerms<T>) {
190 let has_writer_bit: bool = (v & WRITER) != 0;
192 let has_upgrade_bit: bool = (v & UPGRADEABLE_READER) != 0;
193 let has_max_reader_bit: bool = (v & MAX_READER) != 0;
194 let total_reader_bits: int = (v & MAX_READER_MASK) as int;
197 let reader_bits: int = if has_max_reader_bit { MAX_READER as int } else { (v & READER_MASK) as int };
201
202 let active_writer: bool = g.core_token.is_right();
210 let active_upgrade_guard: bool = !active_writer && g.upreader_guard_token is None;
212 let active_read_guards: int = if g.read_guard_token is Left {
214 MAX_READER_U64 - g.read_guard_token.left().frac()
215 } else {
216 0
217 };
218 let pending_failed_upread_attempt: bool = g.upread_retract_token is None;
220 let failed_reader_attempts: int = V_MAX_READ_RETRACT_FRACS - g.read_retract_token.frac();
222
223 &&& if g.core_token.is_left() {
224 g.read_guard_token is Left
225 } else {
226 &&& g.upreader_guard_token is None
227 &&& g.read_guard_token is Right
228 }
229 &&& has_upgrade_bit <==> (active_upgrade_guard || pending_failed_upread_attempt)
231 &&& !(active_upgrade_guard && pending_failed_upread_attempt)
233 &&& total_reader_bits == active_read_guards + failed_reader_attempts
235 &&& active_writer <==> has_writer_bit
237 &&& 0 <= active_read_guards <= reader_bits <= total_reader_bits
239 &&& !(active_writer && (active_read_guards + if active_upgrade_guard { 1int } else { 0 }) > 0)
241 &&& g.core_token.id() == ghost_id@.core_token_id
242 &&& g.core_token.wf()
243 &&& g.core_token.is_left() ==> {
244 &&& !g.core_token.is_resource_owner()
245 &&& g.core_token.frac() == 1
246 }
247 &&& g.core_token.is_right() ==> {
248 let empty = g.core_token.resource_right();
249 &&& empty.id() == ghost_id@.frac_id
250 &&& g.core_token.frac() == 2
251 &&& g.core_token.has_resource()
252 }
253 &&& g.read_retract_token.wf()
254 &&& g.read_retract_token.id() == ghost_id@.read_retract_token_id
255 &&& g.upread_retract_token is Some ==>
256 {
257 let token = g.upread_retract_token->0;
258 &&& token.wf()
259 &&& token.id() == ghost_id@.upread_retract_token_id
260 }
261 &&& g.upreader_guard_token is Some ==> {
262 let token = g.upreader_guard_token->0;
263 wf_upgradeable_guard_token(ghost_id@.core_token_id, ghost_id@.frac_id, val.id(), token)
264 }
265 &&& match g.read_guard_token {
266 Sum::Left(token) => {
267 &&& token.wf()
268 &&& token.id() == ghost_id@.read_guard_token_id
269 &&& token.not_empty() ==> {
270 let resource = token.resource();
271 let read_half_cell_perm = resource.0;
272 let mode_knowledge = resource.1;
273 &&& mode_knowledge.id() == ghost_id@.core_token_id
274 &&& read_half_cell_perm.id() == ghost_id@.frac_id
275 &&& read_half_cell_perm.resource().id() == val.id()
276 &&& read_half_cell_perm.frac() == 1
277 }
278 },
279 Sum::Right(empty) => {
280 &&& empty.id() == ghost_id@.read_guard_token_id
281 },
282 }
283
284 }
285}
286
287}
288
289const READER: usize = 1;
290
291const WRITER: usize = 1 << (usize::BITS - 1);
292
293const UPGRADEABLE_READER: usize = 1 << (usize::BITS - 2);
294
295const BEING_UPGRADED: usize = 1 << (usize::BITS - 3);
296
297const MAX_READER: usize = 1 << (usize::BITS - 4);
312
313const READER_MASK: usize = usize::MAX >> 4;
315
316const MAX_READER_MASK: usize = usize::MAX >> 3;
318
319impl<T, G> RwLock<T, G> {
320 pub closed spec fn cell_id(self) -> cell::CellId {
322 self.val.id()
323 }
324
325 pub closed spec fn core_token_id(self) -> Loc {
326 self.ghost_id@.core_token_id
327 }
328
329 pub closed spec fn frac_id(self) -> Loc {
330 self.ghost_id@.frac_id
331 }
332
333 pub closed spec fn upread_retract_token_id(self) -> Loc {
334 self.ghost_id@.upread_retract_token_id
335 }
336
337 pub closed spec fn read_guard_token_id(self) -> Loc {
338 self.ghost_id@.read_guard_token_id
339 }
340
341 #[verifier::type_invariant]
343 pub closed spec fn type_inv(self) -> bool {
344 self.wf()
345 }
346}
347
348closed spec fn wf_upgradeable_guard_token<T>(
349 core_token_id: Loc,
350 frac_id: Loc,
351 cell_id: CellId,
352 token: OneLeftOwner<HalfPerm<T>, NoPerm<T>, 3>,
353) -> bool {
354 let half_cell_perm = token.resource();
355 &&& token.id() == core_token_id
356 &&& half_cell_perm.id() == frac_id
357 &&& half_cell_perm.resource().id() == cell_id
358 &&& token.has_resource()
359 &&& half_cell_perm.frac() == 1
360 &&& token.wf()
361}
362
363impl<T, G> RwLock<T, G> {
364 pub const fn new(val: T) -> Self {
366 let (val, Tracked(perm)) = PCell::new(val);
367
368 proof {
370 lemma_consts_properties();
371 }
372 let tracked mut frac_perm = Count::<PointsTo<T>>::new(perm);
373 let tracked read_half_cell_perm = frac_perm.split(1int);
374 let ghost frac_id = frac_perm.id();
375 let tracked mut core_token = SumResource::alloc_left(frac_perm);
376 let tracked read_retract_token = TokenResource::<V_MAX_READ_RETRACT_FRACS>::alloc(());
377 let tracked upread_retract_token = UniqueToken::alloc(());
378 let tracked upreader_guard_token = core_token.split_one_left_owner();
379 let tracked left_token = core_token.split_one_left_knowledge();
380 let tracked read_guard_token = CountResource::<ReadPerm<T>, MAX_READER_U64>::alloc(
381 (read_half_cell_perm, left_token),
382 );
383 let ghost ghost_id = RwId {
384 frac_id,
385 core_token_id: core_token.id(),
386 upread_retract_token_id: upread_retract_token.id(),
387 read_retract_token_id: read_retract_token.id(),
388 read_guard_token_id: read_guard_token.id(),
389 };
390 let tracked perms = RwPerms {
391 core_token,
392 read_retract_token,
393 upread_retract_token: Some(upread_retract_token),
394 upreader_guard_token: Some(upreader_guard_token),
395 read_guard_token: Sum::Left(read_guard_token),
396 };
397
398 Self {
399 guard: PhantomData,
400 lock: AtomicUsize::new(Ghost((val, PhantomData, Ghost(ghost_id))), 0, Tracked(perms)),
402 val: val,
404 ghost_id: Ghost(ghost_id),
405 }
406 }
407}
408
409#[verus_verify]
410impl<T , G: SpinGuardian> RwLock<T, G> {
411 #[verifier::exec_allows_no_decreases_clause]
418 pub fn read(&self) -> RwLockReadGuard<'_, T, G> {
419 loop {
420 if let Some(readguard) = self.try_read() {
421 return readguard;
422 } else {
423 core::hint::spin_loop();
424 }
425 }
426 }
427
428 #[verifier::exec_allows_no_decreases_clause]
435 pub fn write(&self) -> RwLockWriteGuard<'_, T, G> {
436 loop {
437 if let Some(writeguard) = self.try_write() {
438 return writeguard;
439 } else {
440 core::hint::spin_loop();
441 }
442 }
443 }
444
445 #[verifier::exec_allows_no_decreases_clause]
456 pub fn upread(&self) -> RwLockUpgradeableGuard<'_, T, G> {
457 loop {
458 if let Some(guard) = self.try_upread() {
459 return guard;
460 } else {
461 core::hint::spin_loop();
462 }
463 }
464 }
465
466 #[verus_spec]
470 pub fn try_read(&self) -> Option<RwLockReadGuard<'_, T, G>> {
471 proof_decl!{
472 let tracked mut read_token: Option<Count<ReadPerm<T>,MAX_READER_U64>> = None;
473 let tracked mut retract_read_token: Option<Token<V_MAX_READ_RETRACT_FRACS>> = None;
474 }
475 proof!{
476 use_type_invariant(self);
477 lemma_consts_properties();
478 }
479 let guard = G::read_guard();
480
481 let lock =
483 atomic_with_ghost!(
484 self.lock => fetch_add(READER);
485 update prev -> next;
486 ghost g => {
487 let prev_usize = prev as usize;
488 let next_usize = next as usize;
489 assume (no_max_reader_overflow(prev_usize));
490 lemma_consts_properties_value(prev_usize);
491 lemma_consts_properties_prev_next(prev_usize, next_usize);
492 if prev_usize & (WRITER | MAX_READER | BEING_UPGRADED) == 0 {
493 let tracked mut tmp = g.read_guard_token.tracked_take_left();
494 read_token = Some(tmp.split_one());
495 g.read_guard_token = Sum::Left(tmp);
496 } else {
497 retract_read_token = Some(g.read_retract_token.split_one());
498 }
499 }
500 );
501 if lock & (WRITER | MAX_READER | BEING_UPGRADED) == 0 {
502 Some(
503 RwLockReadGuard {
504 inner: self,
505 guard,
506 tracked_token: Tracked(read_token.tracked_unwrap()),
507 },
508 )
509 } else {
510 atomic_with_ghost!(
512 self.lock => fetch_sub(READER);
513 update prev -> next;
514 ghost g => {
515 let prev_usize = prev as usize;
516 let next_usize = next as usize;
517 lemma_consts_properties_value(next_usize);
518 lemma_consts_properties_prev_next(prev_usize, next_usize);
519 g.read_retract_token.combine(retract_read_token.tracked_unwrap());
520 }
521 );
522 None
523 }
524 }
525
526 #[verus_spec]
530 pub fn try_write(&self) -> Option<RwLockWriteGuard<'_, T, G>> {
531 proof_decl!{
532 let tracked mut guard_perm: Option<PointsTo<T>> = None;
533 let tracked mut guard_token: Option<OneRightKnowledge<HalfPerm<T>, NoPerm<T>, 3>> = None;
534 }
535 proof!{
536 use_type_invariant(self);
537 lemma_consts_properties();
538 }
539
540 let guard = G::guard();
541 if atomic_with_ghost!(
546 self.lock => compare_exchange(0, WRITER);
547 update prev -> next;
548 returning res;
549 ghost g => {
550 let prev_usize = prev as usize;
551 let next_usize = next as usize;
552 if res is Ok {
553 let tracked read_guard_token = g.read_guard_token.tracked_take_left();
555 let tracked (read_resource, read_empty) = read_guard_token.take_resource();
556 g.read_guard_token = Sum::Right(read_empty);
557 let tracked (read_half_cell_perm, left_token) = read_resource;
558 g.core_token.join_one_left_knowledge(left_token);
559 let tracked upreader_guard_token = g.upreader_guard_token.tracked_take();
561 g.core_token.join_one_left_owner(upreader_guard_token);
562 let tracked mut pointsto = g.core_token.take_resource_left();
564 pointsto.combine(read_half_cell_perm);
565 let tracked (pointsto, empty) = pointsto.take_resource();
566 guard_perm = Some(pointsto);
567 g.core_token.change_to_right(empty);
568 guard_token = Some(g.core_token.split_one_right_knowledge());
569 }
570 }
571 ).is_ok() {
572 Some(
573 RwLockWriteGuard {
574 inner: self,
575 guard,
576 tracked_perm: Tracked(guard_perm.tracked_unwrap()),
577 tracked_token: Tracked(guard_token.tracked_unwrap()),
578 },
579 )
580 } else {
581 None
582 }
583 }
584
585 pub fn try_upread(&self) -> Option<RwLockUpgradeableGuard<'_, T, G>> {
589 proof_decl!{
590 let tracked mut upgrade_guard_token: Option<OneLeftOwner<HalfPerm<T>, NoPerm<T>, 3>> = None;
591 let tracked mut retract_upgrade_token: Option<UniqueToken> = None;
592 }
593 proof!{
594 use_type_invariant(self);
595 lemma_consts_properties();
596 }
597 let guard = G::guard();
598 let lock =
600 atomic_with_ghost!(
601 self.lock => fetch_or(UPGRADEABLE_READER);
602 update prev -> next;
603 ghost g => {
604 lemma_consts_properties_value(prev);
605 lemma_consts_properties_prev_next(prev, next);
606 if prev & (WRITER | UPGRADEABLE_READER) == 0 {
607 upgrade_guard_token = Some(g.upreader_guard_token.tracked_take());
608 }
609 else if prev & (WRITER | UPGRADEABLE_READER) == WRITER {
610 retract_upgrade_token = Some(g.upread_retract_token.tracked_take());
611 }
612 }
613 )
614 & (WRITER | UPGRADEABLE_READER);
615 if lock == 0 {
616 return Some(
617 RwLockUpgradeableGuard {
618 inner: self,
619 guard,
620 tracked_token: Tracked(upgrade_guard_token.tracked_unwrap()),
621 },
622 );
623 } else if lock == WRITER {
624 atomic_with_ghost!(
626 self.lock => fetch_sub(UPGRADEABLE_READER);
627 update prev -> next;
628 ghost g => {
629 let prev_usize = prev as usize;
630 let next_usize = next as usize;
631 lemma_consts_properties_value(prev_usize);
632 lemma_consts_properties_prev_next(prev_usize, next_usize);
633 if g.upread_retract_token is Some {
634 let tracked mut token = retract_upgrade_token.tracked_unwrap();
635 token.validate_with_other(g.upread_retract_token.tracked_borrow());
636 }
637 else{
638 g.upread_retract_token= retract_upgrade_token;
639 }
640 }
641 );
642 }
643 None
644 }
645}
646
647#[verifier::external]
676unsafe impl<T: Send, G> Send for RwLock<T, G> {
677
678}
679
680#[verifier::external]
681unsafe impl<T: Send + Sync, G> Sync for RwLock<T, G> {
682
683}
684
685impl<T , G: SpinGuardian> !Send for RwLockWriteGuard<'_, T, G> {
686
687}
688
689#[verifier::external]
690unsafe impl<T: Sync, G: SpinGuardian> Sync for RwLockWriteGuard<'_, T, G> {
691
692}
693
694impl<T , G: SpinGuardian> !Send for RwLockReadGuard<'_, T, G> {
695
696}
697
698#[verifier::external]
699unsafe impl<T: Sync, G: SpinGuardian> Sync for RwLockReadGuard<'_, T, G> {
700
701}
702
703impl<T , G: SpinGuardian> !Send for RwLockUpgradeableGuard<'_, T, G> {
704
705}
706
707#[verifier::external]
708unsafe impl<T: Sync, G: SpinGuardian> Sync for RwLockUpgradeableGuard<'_, T, G> {
709
710}
711
712#[verifier::reject_recursive_types(T)]
714#[verifier::reject_recursive_types(G)]
715#[clippy::has_significant_drop]
716#[must_use]
717#[verus_verify]
718pub struct RwLockReadGuard<'a, T , G: SpinGuardian> {
719 guard: G::ReadGuard,
720 inner: &'a RwLock<T, G>,
721 tracked_token: Tracked<Count<ReadPerm<T>, MAX_READER_U64>>,
722}
723
724impl<'a, T, G: SpinGuardian> RwLockReadGuard<'a, T, G> {
733 #[verifier::type_invariant]
734 pub closed spec fn type_inv(self) -> bool {
735 let resource = self.tracked_token@.resource();
736 let read_half_cell_perm = resource.0;
737 let mode_knowledge = resource.1;
738 &&& self.inner.core_token_id() == mode_knowledge.id()
739 &&& self.inner.frac_id() == read_half_cell_perm.id()
740 &&& self.inner.cell_id() == read_half_cell_perm.resource().id()
741 &&& self.tracked_token@.id() == self.inner.read_guard_token_id()
742 &&& read_half_cell_perm.frac() == 1
743 &&& self.tracked_token@.frac() == 1
744 }
745
746 pub closed spec fn value(self) -> T {
748 *self.tracked_token@.resource().0.resource().value()
749 }
750
751 pub open spec fn view(self) -> T {
753 self.value()
754 }
755
756 #[verifier::external_body]
758 pub proof fn tracked_borrow(tracked &self) -> (tracked r: &'a T)
759 returns
760 self.view(),
761 {
762 unimplemented!()
763 }
764}
765
766impl<T , G: SpinGuardian> Deref for RwLockReadGuard<'_, T, G> {
767 type Target = T;
768
769 #[verus_spec(returns self.view())]
770 fn deref(&self) -> &T {
771 proof!{
772 use_type_invariant(self);
773 }
774 self.inner.val.borrow(Tracked(self.tracked_token.borrow().borrow().0.borrow()))
778 }
779}
780
781#[verus_verify]
790impl<T , G: SpinGuardian> RwLockReadGuard<'_, T, G> {
791 #[verus_spec]
793 fn drop(self) {
794 proof! {
795 use_type_invariant(&self);
796 use_type_invariant(self.inner);
797 lemma_consts_properties();
798 }
799 proof_decl! {
800 let tracked token = self.tracked_token.get();
801 }
802 atomic_with_ghost!(
804 self.inner.lock => fetch_sub(READER);
805 update prev -> next;
806 ghost g => {
807 let prev_usize = prev as usize;
808 let next_usize = next as usize;
809 assume (no_max_reader_overflow(prev_usize));
810 lemma_consts_properties_value(next_usize);
811 lemma_consts_properties_prev_next(prev_usize, next_usize);
812 g.core_token.validate_with_one_left_knowledge(&token.borrow().1);
813 let tracked mut tmp = g.read_guard_token.tracked_take_left();
814 tmp.combine(token);
815 g.read_guard_token = Sum::Left(tmp);
816 }
817 );
818 }
819}
820
821#[verifier::reject_recursive_types(T)]
830#[verifier::reject_recursive_types(G)]
831pub struct RwLockWriteGuard<'a, T , G: SpinGuardian> {
832 guard: G::Guard,
833 inner: &'a RwLock<T, G>,
834 tracked_perm: Tracked<PointsTo<T>>,
836 tracked_token: Tracked<OneRightKnowledge<HalfPerm<T>, NoPerm<T>, 3>>,
837}
838
839impl<'a, T, G: SpinGuardian> RwLockWriteGuard<'a, T, G> {
840 #[verifier::type_invariant]
841 spec fn type_inv(self) -> bool {
842 &&& self.inner.cell_id() == self.tracked_perm@.id()
843 &&& self.inner.core_token_id() == self.tracked_token@.id()
844 }
845
846 pub closed spec fn value(self) -> T {
848 *self.tracked_perm@.value()
849 }
850
851 pub open spec fn view(self) -> T {
853 self.value()
854 }
855
856 #[verifier::external_body]
858 pub proof fn tracked_borrow(tracked &self) -> (tracked r: &'a T)
859 returns
860 self.view(),
861 {
862 unimplemented!()
863 }
864}
865
866impl<T , G: SpinGuardian> Deref for RwLockWriteGuard<'_, T, G> {
874 type Target = T;
875
876 #[verus_spec(returns self.view())]
877 fn deref(&self) -> &T {
878 proof!{
879 use_type_invariant(self);
880 }
881 self.inner.val.borrow(Tracked(self.tracked_perm.borrow()))
885 }
886}
887
888#[verus_verify]
889impl<T , G: SpinGuardian> DerefMut for RwLockWriteGuard<'_, T, G> {
890 #[verus_spec(ret =>
891 ensures
892 final(self).view() == *final(ret),
893 old(self).view() == *ret,
894 )]
895 fn deref_mut(&mut self) -> &mut Self::Target {
896 proof!{
897 use_type_invariant(&*self);
898 }
899 self.inner.val.borrow_mut(Tracked(&mut *self.tracked_perm))
901 }
902}
903
904impl<T , G: SpinGuardian> RwLockWriteGuard<'_, T, G> {
912 pub fn drop(self) {
914 proof!{
915 use_type_invariant(&self);
916 use_type_invariant(self.inner);
917 lemma_consts_properties();
918 }
919 proof_decl! {
920 let tracked mut perm = self.tracked_perm.get();
921 let tracked token = self.tracked_token.get();
922 }
923 atomic_with_ghost!{
925 self.inner.lock => fetch_and(!WRITER);
926 update prev -> next;
927 ghost g => {
928 let prev_usize = prev as usize;
929 let next_usize = next as usize;
930 lemma_consts_properties_prev_next(prev_usize, next_usize);
931 lemma_consts_properties_value(next_usize);
932 g.core_token.validate_with_one_right_knowledge(&token);
933 g.core_token.join_one_right_knowledge(token);
934 let tracked empty = g.core_token.take_resource_right();
935 let tracked mut full = empty.put_resource(perm);
936 let tracked read_half_cell_perm = full.split(1int);
937 g.core_token.change_to_left(full);
938 let tracked upreader_guard_token = g.core_token.split_one_left_owner();
939 g.upreader_guard_token = Some(upreader_guard_token);
940 let tracked left_token = g.core_token.split_one_left_knowledge();
941 let tracked read_guard_empty = g.read_guard_token.tracked_take_right();
942 let tracked read_guard_token = CountResource::alloc_from_empty(
943 read_guard_empty,
944 (read_half_cell_perm, left_token),
945 );
946 g.read_guard_token = Sum::Left(read_guard_token);
947 }
948 };
949 }
950}
951
952#[verifier::reject_recursive_types(T)]
962#[verifier::reject_recursive_types(G)]
963pub struct RwLockUpgradeableGuard<'a, T , G: SpinGuardian> {
964 guard: G::Guard,
965 inner: &'a RwLock<T, G>,
966 tracked_token: Tracked<OneLeftOwner<HalfPerm<T>, NoPerm<T>, 3>>,
967}
968
969impl<'a, T, G: SpinGuardian> RwLockUpgradeableGuard<'a, T, G> {
977 #[verifier::type_invariant]
978 pub closed spec fn type_inv(self) -> bool {
979 wf_upgradeable_guard_token(
980 self.inner.core_token_id(),
981 self.inner.frac_id(),
982 self.inner.cell_id(),
983 self.tracked_token@,
984 )
985 }
986
987 pub closed spec fn value(self) -> T {
989 *self.tracked_token@.resource().resource().value()
990 }
991
992 pub open spec fn view(self) -> T {
994 self.value()
995 }
996}
997
998impl<'a, T , G: SpinGuardian> RwLockUpgradeableGuard<'a, T, G> {
999 #[verifier::exec_allows_no_decreases_clause]
1005 pub fn upgrade( self) -> RwLockWriteGuard<'a, T, G> {
1006 let mut this = self;
1007 proof! {
1008 use_type_invariant(&this);
1009 use_type_invariant(&this.inner);
1010 lemma_consts_properties();
1011 }
1012 atomic_with_ghost!(
1014 this.inner.lock => fetch_or(BEING_UPGRADED);
1015 update prev -> next;
1016 ghost g => {
1017 lemma_consts_properties_prev_next(prev, next);
1018 }
1019 );
1020 loop {
1021 this =
1023 match this.try_upgrade() {
1024 Ok(guard) => return guard,
1025 Err(e) => e,
1026 };
1027 }
1028 }
1029
1030 fn try_upgrade( self) -> Result<RwLockWriteGuard<'a, T, G>, Self> {
1037 proof! {
1038 use_type_invariant(&self);
1039 use_type_invariant(self.inner);
1040 lemma_consts_properties();
1041 }
1042 let mut this = self;
1043 proof_decl! {
1044 let tracked mut upread_guard_token = this.tracked_token.get();
1045 let tracked mut write_perm: Option<PointsTo<T>> = None;
1046 let tracked mut err_upread_guard_token: Option<OneLeftOwner<HalfPerm<T>, NoPerm<T>, 3>> = None;
1047 let tracked mut retract_upgrade_token: Option<UniqueToken> = None;
1048 let tracked mut write_guard_token = None;
1049 }
1050
1051 let res =
1058 atomic_with_ghost!(
1059 this.inner.lock => compare_exchange(UPGRADEABLE_READER | BEING_UPGRADED, WRITER | UPGRADEABLE_READER);
1060 update prev -> next;
1061 returning res;
1062 ghost g => {
1063 lemma_consts_properties_prev_next(prev, next);
1064 if res is Ok {
1065 g.core_token.validate_with_one_left_owner(&upread_guard_token);
1066 if g.upreader_guard_token is Some {
1067 upread_guard_token.validate_with_one_left_owner(g.upreader_guard_token.tracked_borrow());
1068 }
1069 g.core_token.join_one_left_owner(upread_guard_token);
1070 let tracked read_guard_token = g.read_guard_token.tracked_take_left();
1071 let tracked (read_resource, read_empty) = read_guard_token.take_resource();
1072 g.read_guard_token = Sum::Right(read_empty);
1073 let tracked (read_half_cell_perm, left_token) = read_resource;
1074 g.core_token.join_one_left_knowledge(left_token);
1075 let tracked mut pointsto = g.core_token.take_resource_left();
1076 pointsto.combine(read_half_cell_perm);
1077 let tracked (pointsto, empty) = pointsto.take_resource();
1078 write_perm = Some(pointsto);
1079 g.core_token.change_to_right(empty);
1080 write_guard_token = Some(g.core_token.split_one_right_knowledge());
1081 retract_upgrade_token = Some(g.upread_retract_token.tracked_take());
1082 } else {
1083 err_upread_guard_token = Some(upread_guard_token);
1084 }
1085 }
1086 );
1087 if res.is_ok() {
1088 let inner = this.inner;
1089 let guard = this.guard.transfer_to();
1090 atomic_with_ghost!(
1092 inner.lock => fetch_sub(UPGRADEABLE_READER);
1093 update prev -> next;
1094 ghost g => {
1095 let prev_usize = prev as usize;
1096 let next_usize = next as usize;
1097 lemma_consts_properties_value(prev_usize);
1098 lemma_consts_properties_prev_next(prev_usize, next_usize);
1099 let tracked mut token = retract_upgrade_token.tracked_unwrap();
1100 if g.upread_retract_token is Some {
1101 token.validate_with_other(g.upread_retract_token.tracked_borrow());
1102 }
1103 g.upread_retract_token = Some(token);
1104 }
1105 );
1106 Ok(
1107 RwLockWriteGuard {
1108 inner,
1109 guard,
1110 tracked_perm: Tracked(write_perm.tracked_unwrap()),
1111 tracked_token: Tracked(write_guard_token.tracked_unwrap()),
1112 },
1113 )
1114 } else {
1115 Err(
1116 RwLockUpgradeableGuard {
1117 inner: this.inner,
1118 guard: this.guard,
1119 tracked_token: Tracked(err_upread_guard_token.tracked_unwrap()),
1120 },
1121 )
1122 }
1123 }
1124}
1125
1126impl<T , G: SpinGuardian> Deref for RwLockUpgradeableGuard<'_, T, G> {
1127 type Target = T;
1128
1129 #[verus_spec(returns self.view())]
1130 fn deref(&self) -> &T {
1131 proof!{
1132 use_type_invariant(self);
1133 }
1134 self.inner.val.borrow(Tracked(self.tracked_token.borrow().tracked_borrow().borrow()))
1138 }
1139}
1140
1141impl<T , G: SpinGuardian> RwLockUpgradeableGuard<'_, T, G> {
1149 pub fn drop(self) {
1151 proof! {
1152 use_type_invariant(&self);
1153 use_type_invariant(self.inner);
1154 lemma_consts_properties();
1155 }
1156 proof_decl!{
1157 let tracked guard_token = self.tracked_token.get();
1158 }
1159 atomic_with_ghost!(
1161 self.inner.lock => fetch_sub(UPGRADEABLE_READER);
1162 update prev -> next;
1163 ghost g => {
1164 let prev_usize = prev as usize;
1165 let next_usize = next as usize;
1166 lemma_consts_properties_value(prev_usize);
1167 lemma_consts_properties_prev_next(prev_usize, next_usize);
1168 g.core_token.validate_with_one_left_owner(&guard_token);
1169 if g.upreader_guard_token is Some {
1170 guard_token.validate_with_one_left_owner(g.upreader_guard_token.tracked_borrow());
1171 assert(false);
1172 } else {
1173 g.upreader_guard_token= Some(guard_token);
1174 }
1175 }
1176 );
1177 }
1178}
1179
1180#[verifier::bit_vector]
1189proof fn lemma_consts_properties()
1190 ensures
1191 0 & WRITER == 0,
1192 0 & UPGRADEABLE_READER == 0,
1193 0 & BEING_UPGRADED == 0,
1194 0 & READER_MASK == 0,
1195 0 & MAX_READER_MASK == 0,
1196 0 & MAX_READER == 0,
1197 0 & READER == 0,
1198 WRITER == 0x8000_0000_0000_0000,
1199 UPGRADEABLE_READER == 0x4000_0000_0000_0000,
1200 BEING_UPGRADED == 0x2000_0000_0000_0000,
1201 READER_MASK == 0x0FFF_FFFF_FFFF_FFFF,
1202 MAX_READER_MASK == 0x1FFF_FFFF_FFFF_FFFF,
1203 MAX_READER == 0x1000_0000_0000_0000,
1204 WRITER & WRITER == WRITER,
1205 WRITER & !WRITER == 0,
1206 WRITER & BEING_UPGRADED == 0,
1207 WRITER & READER_MASK == 0,
1208 WRITER & MAX_READER_MASK == 0,
1209 WRITER & MAX_READER == 0,
1210 WRITER & UPGRADEABLE_READER == 0,
1211 BEING_UPGRADED & WRITER == 0,
1212 BEING_UPGRADED & UPGRADEABLE_READER == 0,
1213 UPGRADEABLE_READER & BEING_UPGRADED == 0,
1214 UPGRADEABLE_READER & READER_MASK == 0,
1215 UPGRADEABLE_READER & MAX_READER_MASK == 0,
1216 UPGRADEABLE_READER & MAX_READER == 0,
1217 BEING_UPGRADED & READER_MASK == 0,
1218 BEING_UPGRADED & MAX_READER_MASK == 0,
1219 BEING_UPGRADED & MAX_READER == 0,
1220 (UPGRADEABLE_READER | BEING_UPGRADED) & WRITER == 0,
1221 (UPGRADEABLE_READER | BEING_UPGRADED) & UPGRADEABLE_READER == UPGRADEABLE_READER,
1222 (UPGRADEABLE_READER | BEING_UPGRADED) & BEING_UPGRADED == BEING_UPGRADED,
1223 (UPGRADEABLE_READER | BEING_UPGRADED) & READER_MASK == 0,
1224 (UPGRADEABLE_READER | BEING_UPGRADED) & MAX_READER_MASK == 0,
1225 (UPGRADEABLE_READER | BEING_UPGRADED) & MAX_READER == 0,
1226 (WRITER | UPGRADEABLE_READER) & WRITER == WRITER,
1227 (WRITER | UPGRADEABLE_READER) & UPGRADEABLE_READER == UPGRADEABLE_READER,
1228 (WRITER | UPGRADEABLE_READER) & BEING_UPGRADED == 0,
1229 (WRITER | UPGRADEABLE_READER) & READER_MASK == 0,
1230 (WRITER | UPGRADEABLE_READER) & MAX_READER_MASK == 0,
1231 (WRITER | UPGRADEABLE_READER) & MAX_READER == 0,
1232{
1233}
1234
1235#[verifier::bit_vector]
1236proof fn lemma_consts_properties_value(prev: usize)
1237 ensures
1238 no_max_reader_overflow(prev) ==> prev + READER <= usize::MAX,
1239 prev & (WRITER | MAX_READER | BEING_UPGRADED) == 0 ==> {
1240 &&& prev & WRITER == 0
1241 &&& prev & BEING_UPGRADED == 0
1242 &&& prev & MAX_READER == 0
1243 },
1244 prev & (WRITER | UPGRADEABLE_READER) == 0 ==> {
1245 &&& prev & WRITER == 0
1246 &&& prev & UPGRADEABLE_READER == 0
1247 },
1248 prev & MAX_READER == 0 ==> prev & READER_MASK == prev & MAX_READER_MASK,
1249 prev & MAX_READER != 0 ==> prev & MAX_READER_MASK >= MAX_READER,
1250 prev & (WRITER | UPGRADEABLE_READER) == WRITER ==> {
1251 &&& prev & UPGRADEABLE_READER == 0
1252 &&& prev & WRITER == WRITER
1253 },
1254 prev & UPGRADEABLE_READER != 0 ==> prev >= UPGRADEABLE_READER,
1255 prev & UPGRADEABLE_READER == 0 ==> {
1256 ||| prev & (WRITER | UPGRADEABLE_READER) == 0
1257 ||| prev & (WRITER | UPGRADEABLE_READER) == WRITER
1258 },
1259{
1260}
1261
1262#[verifier::bit_vector]
1263proof fn lemma_consts_properties_prev_next(prev: usize, next: usize)
1264 ensures
1265 prev & READER_MASK < MAX_READER,
1266 next == prev | UPGRADEABLE_READER ==> {
1267 &&& next & UPGRADEABLE_READER != 0
1268 &&& next & WRITER == prev & WRITER
1269 &&& next & READER_MASK == prev & READER_MASK
1270 &&& next & MAX_READER_MASK == prev & MAX_READER_MASK
1271 &&& next & MAX_READER == prev & MAX_READER
1272 &&& next & BEING_UPGRADED == prev & BEING_UPGRADED
1273 },
1274 next == prev | BEING_UPGRADED ==> {
1275 &&& next & BEING_UPGRADED != 0
1276 &&& next & WRITER == prev & WRITER
1277 &&& next & UPGRADEABLE_READER == prev & UPGRADEABLE_READER
1278 &&& next & READER_MASK == prev & READER_MASK
1279 &&& next & MAX_READER_MASK == prev & MAX_READER_MASK
1280 &&& next & MAX_READER == prev & MAX_READER
1281 },
1282 next == prev - UPGRADEABLE_READER && prev & UPGRADEABLE_READER != 0 ==> {
1283 &&& next & UPGRADEABLE_READER == 0
1284 &&& next & WRITER == prev & WRITER
1285 &&& next & READER_MASK == prev & READER_MASK
1286 &&& next & MAX_READER_MASK == prev & MAX_READER_MASK
1287 &&& next & MAX_READER == prev & MAX_READER
1288 &&& next & BEING_UPGRADED == prev & BEING_UPGRADED
1289 },
1290 next == prev - READER && prev & READER_MASK != 0 ==> {
1291 &&& next & READER_MASK == (prev & READER_MASK) - READER
1292 &&& next & MAX_READER_MASK == (prev & MAX_READER_MASK) - READER
1293 &&& next & UPGRADEABLE_READER == prev & UPGRADEABLE_READER
1294 &&& next & WRITER == prev & WRITER
1295 &&& next & MAX_READER == prev & MAX_READER
1296 &&& next & BEING_UPGRADED == prev & BEING_UPGRADED
1297 },
1298 next == prev - READER && prev & MAX_READER_MASK != 0 ==> {
1299 &&& next & MAX_READER_MASK == (prev & MAX_READER_MASK) - READER
1300 &&& next & UPGRADEABLE_READER == prev & UPGRADEABLE_READER
1301 &&& next & WRITER == prev & WRITER
1302 &&& next & BEING_UPGRADED == prev & BEING_UPGRADED
1303 },
1304 next == prev + READER && no_max_reader_overflow(prev) ==> {
1305 &&& next & READER_MASK == if (prev & READER_MASK) + READER == MAX_READER {
1306 0
1307 } else {
1308 (prev & READER_MASK) + READER
1309 }
1310 &&& next & MAX_READER_MASK == (prev & MAX_READER_MASK) + READER
1311 &&& next & UPGRADEABLE_READER == prev & UPGRADEABLE_READER
1312 &&& next & WRITER == prev & WRITER
1313 &&& next & MAX_READER == if (prev & READER_MASK) + READER == MAX_READER {
1314 MAX_READER
1315 } else {
1316 prev & MAX_READER
1317 }
1318 &&& next & BEING_UPGRADED == prev & BEING_UPGRADED
1319 },
1320 next == prev & !WRITER ==> {
1321 &&& next & WRITER == 0
1322 &&& next & UPGRADEABLE_READER == prev & UPGRADEABLE_READER
1323 &&& next & READER_MASK == prev & READER_MASK
1324 &&& next & MAX_READER_MASK == prev & MAX_READER_MASK
1325 &&& next & MAX_READER == prev & MAX_READER
1326 &&& next & BEING_UPGRADED == prev & BEING_UPGRADED
1327 },
1328{
1329}
1330
1331}