@@ -41,6 +41,7 @@ type NoPerm<T> = Empty<PointsTo<T>, V_MAX_PERM_FRACS>;
4141type UpreaderGuardToken = UniqueToken ;
4242
4343type ReadRetractToken = TokenStorage <V_MAX_READ_RETRACT_FRACS >;
44+ type ReadGuardToken = TokenStorage <V_MAX_READ_GUARDS >;
4445
4546spec const V_MAX_PERM_FRACS_SPEC : u64 = ( MAX_READER + 2 ) as u64 ;
4647
@@ -68,6 +69,19 @@ exec const V_MAX_READ_RETRACT_FRACS: u64
6869 ( MAX_READER_MASK + 1 ) as u64
6970}
7071
72+ spec const V_MAX_READ_GUARDS_SPEC : u64 = MAX_READER as u64 ;
73+
74+ #[ verifier:: when_used_as_spec( V_MAX_READ_GUARDS_SPEC ) ]
75+ exec const V_MAX_READ_GUARDS : u64
76+ ensures
77+ V_MAX_READ_GUARDS == V_MAX_READ_GUARDS_SPEC ,
78+ V_MAX_READ_GUARDS == MAX_READER ,
79+ V_MAX_READ_GUARDS < u64 :: MAX ,
80+ {
81+ assert( MAX_READER < u64 :: MAX ) by ( compute_only) ;
82+ MAX_READER as u64
83+ }
84+
7185tracked struct RwPerms <T > {
7286 /// The fractional permission of the `PCell<T>`. It can be splited up to `V_MAX_PERM_FRACS:= MAX_READER + 2` pieces,
7387 /// which allows at most `MAX_READER` `RwLockReadGuard`s and 1 `RwLockUpgradeableGuard`, and 1 reserved in the lock atomic.
@@ -79,6 +93,8 @@ tracked struct RwPerms<T> {
7993 /// It can be splited up to `V_MAX_READ_RETRACT_FRACS:= 2 * MAX_READER` pieces,
8094 /// which allows at most `2*MAX_READER - 1` `try_read` attempts that will fail to acquire the lock, and 1 reserved in the lock atomic.
8195 read_retract_token: ReadRetractToken ,
96+ /// Tracks live `RwLockReadGuard`s.
97+ read_guard_token: ReadGuardToken ,
8298 /// The permission to retract the set of `UPGRADEABLE_READER` bit, it can be spilit at two pieces,
8399 /// which allows at most 1 failing `try_upread` to subtract the `UPGRADEABLE_READER` bit, and 1 reserved in the lock atomic.
84100 upgrade_retract_token: UniqueTokenStorage ,
@@ -91,6 +107,7 @@ ghost struct RwId {
91107 upgrade_retract_token_id: Loc ,
92108 upreader_guard_token_id: Loc ,
93109 read_retract_token_id: Loc ,
110+ read_guard_token_id: Loc ,
94111}
95112
96113/// The number of `try_read` operations recorded in the lock atomic (created and ongoing) can never reach `2*MAX_READER` to avoid overflow.
@@ -226,6 +243,7 @@ closed spec fn wf(self) -> bool {
226243 // The number of `try_read` attempts that will fail.
227244 let failed_reader_attempts: int = total_reader_attempts + upgrade_reader_count - total_successful_readers;
228245 &&& g. read_retract_token. frac( ) + failed_reader_attempts == V_MAX_READ_RETRACT_FRACS
246+ &&& g. read_guard_token. frac( ) + successful_read_guards == V_MAX_READ_GUARDS
229247 &&& has_upgrade <==> ( has_upreader_guard || pending_failed_upgrade_attempt)
230248 &&& !( has_upreader_guard && pending_failed_upgrade_attempt)
231249 &&& g. upreader_guard_token. is_empty( ) ==> ( v & UPGRADEABLE_READER ) != 0usize
@@ -237,6 +255,7 @@ closed spec fn wf(self) -> bool {
237255 &&& g. cell_perm is Right <==> has_writer
238256 &&& 0 <= successful_read_guards <= reader_count <= total_reader_attempts
239257 &&& 0 <= g. read_retract_token. frac( ) <= V_MAX_READ_RETRACT_FRACS
258+ &&& 0 <= g. read_guard_token. frac( ) <= V_MAX_READ_GUARDS
240259 &&& pending_failed_upgrade_attempt ==> has_upgrade
241260 &&& match g. cell_perm {
242261 Sum :: Right ( empty) => {
@@ -252,6 +271,7 @@ closed spec fn wf(self) -> bool {
252271 &&& v_id@. upgrade_retract_token_id == g. upgrade_retract_token. id( )
253272 &&& v_id@. upreader_guard_token_id == g. upreader_guard_token. id( )
254273 &&& v_id@. read_retract_token_id == g. read_retract_token. id( )
274+ &&& v_id@. read_guard_token_id == g. read_guard_token. id( )
255275 }
256276}
257277
@@ -319,17 +339,20 @@ impl<T, G> RwLock<T, G> {
319339 proof { lemma_consts_properties( ) ; }
320340 let tracked frac_perm = RwFrac :: <T >:: new( perm) ;
321341 let tracked read_retract_token = TokenStorage :: <V_MAX_READ_RETRACT_FRACS >:: new( ( ) ) ;
342+ let tracked read_guard_token = TokenStorage :: <V_MAX_READ_GUARDS >:: new( ( ) ) ;
322343 let tracked upgrade_retract_token = UniqueTokenStorage :: new( ( ) ) ;
323344 let tracked upreader_guard_token = UniqueTokenStorage :: new( ( ) ) ;
324345 let ghost v_id = RwId {
325346 cell_perm_id: frac_perm. id( ) ,
326347 upgrade_retract_token_id: upgrade_retract_token. id( ) ,
327348 upreader_guard_token_id: upreader_guard_token. id( ) ,
328349 read_retract_token_id: read_retract_token. id( ) ,
350+ read_guard_token_id: read_guard_token. id( ) ,
329351 } ;
330352 let tracked perms = RwPerms {
331353 cell_perm: Sum :: new_left( frac_perm) ,
332354 read_retract_token,
355+ read_guard_token,
333356 upgrade_retract_token,
334357 upreader_guard_token,
335358 } ;
@@ -410,6 +433,7 @@ impl<T /*: ?Sized*/ , G: SpinGuardian> RwLock<T, G> {
410433 pub fn try_read( & self ) -> Option <RwLockReadGuard <T , G >> {
411434 proof_decl!{
412435 let tracked mut perm: Option <RwFrac <T >> = None ;
436+ let tracked mut read_guard_token: Option <Token <V_MAX_READ_GUARDS >> = None ;
413437 let tracked mut retract_read_token: Option <Token <V_MAX_READ_RETRACT_FRACS >> = None ;
414438 }
415439 proof!{
@@ -433,14 +457,21 @@ impl<T /*: ?Sized*/ , G: SpinGuardian> RwLock<T, G> {
433457 let tracked mut tmp = g. cell_perm. tracked_take_left( ) ;
434458 perm = Some ( tmp. split( 1 int) ) ;
435459 g. cell_perm = Sum :: new_left( tmp) ;
460+ g. read_guard_token. bounded( ) ;
461+ read_guard_token = Some ( g. read_guard_token. split_one( ) ) ;
436462 } else {
437463 g. read_retract_token. bounded( ) ;
438464 retract_read_token = Some ( g. read_retract_token. split_one( ) ) ;
439465 }
440466 }
441467 ) ;
442468 if lock & ( WRITER | MAX_READER | BEING_UPGRADED ) == 0 {
443- Some ( RwLockReadGuard { inner: self , guard, v_perm: Tracked ( perm. tracked_unwrap( ) ) } )
469+ Some ( RwLockReadGuard {
470+ inner: self ,
471+ guard,
472+ v_perm: Tracked ( perm. tracked_unwrap( ) ) ,
473+ v_token: Tracked ( read_guard_token. tracked_unwrap( ) ) ,
474+ } )
444475 } else {
445476 // self.lock.fetch_sub(READER, Release);
446477 atomic_with_ghost!(
@@ -635,6 +666,7 @@ pub struct RwLockReadGuard<'a, T /*: ?Sized*/, G: SpinGuardian> {
635666 guard: G :: ReadGuard ,
636667 inner: & ' a RwLock <T , G >,
637668 v_perm: Tracked <RwFrac <T >>,
669+ v_token: Tracked <Token <V_MAX_READ_GUARDS >>,
638670}
639671
640672/*
@@ -653,6 +685,8 @@ impl<'a, T, G: SpinGuardian> RwLockReadGuard<'a, T, G> {
653685 &&& self . inner. cell_perm_id( ) == self . v_perm@. id( )
654686 &&& self . inner. cell_id( ) == self . v_perm@. resource( ) . id( )
655687 &&& self . v_perm@. frac( ) == 1
688+ &&& self . v_token@. id( ) == self . inner. v_id@. read_guard_token_id
689+ &&& self . v_token@. frac( ) == 1
656690 }
657691}
658692}
@@ -677,19 +711,129 @@ impl<T /*: ?Sized*/, G: SpinGuardian> Deref for RwLockReadGuard<'_, T, G>
677711 }
678712}
679713
714+ /* impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian> Drop
715+ for RwLockReadGuard_<T, R, G>
716+ {
717+ fn drop(&mut self) {
718+ self.inner.lock.fetch_sub(READER, Release);
719+ }
720+ } */
721+
680722verus!{
681- # [ verus_verify ]
682- impl <T /*: ?Sized*/ , G : SpinGuardian > Drop for RwLockReadGuard <' _, T , G >
723+
724+ impl <T /*: ?Sized*/ , G : SpinGuardian > RwLockReadGuard <' _, T , G >
683725{
684- #[ verifier:: external_body]
685- fn drop( & mut self )
686- opens_invariants none
687- no_unwind
726+ /// VERUS LIMITATION: We implement `drop` and call it manually because Verus's support for `Drop` is incomplete for now.
727+ #[ verus_spec]
728+ fn drop( self )
688729 {
730+ proof! {
731+ use_type_invariant( & self ) ;
732+ use_type_invariant( self . inner) ;
733+ lemma_consts_properties( ) ;
734+ }
735+ let Tracked ( perm) = self . v_perm;
736+ let Tracked ( token) = self . v_token;
689737 // self.inner.lock.fetch_sub(READER, Release);
690738 atomic_with_ghost!(
691- & self . inner. lock => fetch_sub( READER ) ;
692- ghost g => { }
739+ self . inner. lock => fetch_sub( READER ) ;
740+ update prev -> next;
741+ ghost g => {
742+ let prev_usize = prev as usize ;
743+ let next_usize = next as usize ;
744+ lemma_consts_properties_value( prev_usize) ;
745+ lemma_consts_properties_prev_next( prev_usize, next_usize) ;
746+ let ghost total_successful_readers =
747+ if g. cell_perm is Left {
748+ ( V_MAX_PERM_FRACS as int) - g. cell_perm->Left_0 . frac( )
749+ } else {
750+ 0 int
751+ } ;
752+ let ghost pending_failed_upgrade_attempt = g. upgrade_retract_token. is_empty( ) ;
753+ let ghost upgrade_reader_count =
754+ if ( prev_usize & UPGRADEABLE_READER ) != 0 && !pending_failed_upgrade_attempt {
755+ 1 int
756+ } else {
757+ 0 int
758+ } ;
759+ let ghost successful_read_guards = total_successful_readers - upgrade_reader_count;
760+ let ghost old_read_guard_frac = g. read_guard_token. frac( ) ;
761+ assert( old_read_guard_frac + successful_read_guards == V_MAX_READ_GUARDS as int) ;
762+ g. read_guard_token. combine( token) ;
763+ g. read_guard_token. bounded( ) ;
764+ assert( old_read_guard_frac + 1 int <= V_MAX_READ_GUARDS as int) ;
765+ assert( old_read_guard_frac < V_MAX_READ_GUARDS as int) ;
766+ assert( successful_read_guards > 0 ) ;
767+ assert( total_successful_readers > 0 ) ;
768+ assert( ( prev_usize & MAX_READER_MASK ) != 0 ) ;
769+ if g. cell_perm is Right {
770+ assert( total_successful_readers == 0 ) ;
771+ assert( false ) ;
772+ }
773+ assert( ( prev_usize & WRITER ) == 0 ) ;
774+ let ghost old_remaining_pcell_perms = g. cell_perm->Left_0 . frac( ) ;
775+ let tracked mut rem = g. cell_perm. tracked_take_left( ) ;
776+ rem. combine( perm) ;
777+ rem. bounded( ) ;
778+ assert( rem. frac( ) == old_remaining_pcell_perms + 1 int) ;
779+ assert( ( V_MAX_PERM_FRACS as int) - rem. frac( ) == total_successful_readers - 1 int) ;
780+ assert( ( next_usize & MAX_READER_MASK ) as int == ( prev_usize & MAX_READER_MASK ) as int - 1 int) ;
781+ assert( ( next_usize & UPGRADEABLE_READER ) == ( prev_usize & UPGRADEABLE_READER ) ) ;
782+ assert( ( next_usize & WRITER ) == ( prev_usize & WRITER ) ) ;
783+ assert( ( next_usize & BEING_UPGRADED ) == ( prev_usize & BEING_UPGRADED ) ) ;
784+ assert( ( next_usize & WRITER ) == 0 ) ;
785+ assert( g. read_guard_token. frac( ) + ( successful_read_guards - 1 int) == V_MAX_READ_GUARDS as int) ;
786+ g. cell_perm = Sum :: new_left( rem) ;
787+ let ghost next_pending_failed_upgrade_attempt = g. upgrade_retract_token. is_empty( ) ;
788+ assert( next_pending_failed_upgrade_attempt == pending_failed_upgrade_attempt) ;
789+ let ghost next_upgrade_reader_count =
790+ if ( next_usize & UPGRADEABLE_READER ) != 0 && !next_pending_failed_upgrade_attempt {
791+ 1 int
792+ } else {
793+ 0 int
794+ } ;
795+ assert( next_upgrade_reader_count == upgrade_reader_count) ;
796+ let ghost next_total_successful_readers =
797+ if g. cell_perm is Left {
798+ ( V_MAX_PERM_FRACS as int) - g. cell_perm->Left_0 . frac( )
799+ } else {
800+ 0 int
801+ } ;
802+ assert( next_total_successful_readers == total_successful_readers - 1 int) ;
803+ let ghost next_successful_read_guards = next_total_successful_readers - next_upgrade_reader_count;
804+ assert( next_successful_read_guards == successful_read_guards - 1 int) ;
805+ assert( g. read_guard_token. frac( ) + next_successful_read_guards == V_MAX_READ_GUARDS as int) ;
806+ let ghost next_total_reader_attempts = ( next_usize & MAX_READER_MASK ) as int;
807+ assert( next_total_reader_attempts == ( prev_usize & MAX_READER_MASK ) as int - 1 int) ;
808+ let ghost next_reader_count =
809+ if ( next_usize & MAX_READER ) != 0 {
810+ MAX_READER as int
811+ } else {
812+ ( next_usize & READER_MASK ) as int
813+ } ;
814+ let ghost next_failed_reader_attempts =
815+ next_total_reader_attempts + next_upgrade_reader_count - next_total_successful_readers;
816+ let ghost failed_reader_attempts =
817+ ( ( prev_usize & MAX_READER_MASK ) as int) + upgrade_reader_count - total_successful_readers;
818+ assert( next_failed_reader_attempts == failed_reader_attempts) ;
819+ assert( g. read_retract_token. frac( ) + next_failed_reader_attempts == V_MAX_READ_RETRACT_FRACS ) ;
820+ assert( 0 <= next_successful_read_guards) ;
821+ if ( next_usize & MAX_READER ) != 0 {
822+ assert( next_reader_count == MAX_READER as int) ;
823+ assert( ( next_usize & MAX_READER_MASK ) >= MAX_READER ) by ( bit_vector)
824+ requires
825+ ( next_usize & MAX_READER ) != 0 ,
826+ ;
827+ } else {
828+ assert( ( next_usize & MAX_READER_MASK ) == ( next_usize & READER_MASK ) ) by ( bit_vector)
829+ requires
830+ ( next_usize & MAX_READER ) == 0 ,
831+ ;
832+ assert( next_reader_count == next_total_reader_attempts) ;
833+ }
834+ assert( next_reader_count <= next_total_reader_attempts) ;
835+ assert( next_successful_read_guards <= next_reader_count) ;
836+ }
693837 ) ;
694838 }
695839}
@@ -1065,7 +1209,7 @@ impl<T /*: ?Sized*/, G: SpinGuardian> RwLockUpgradeableGuard<'_, T, G>
10651209 use_type_invariant( self . inner) ;
10661210 lemma_consts_properties( ) ;
10671211 }
1068- let Tracked ( perm) = self . v_perm;
1212+ let Tracked ( perm) = self . v_perm;
10691213 let Tracked ( token) = self . v_token;
10701214 //self.inner.lock.fetch_sub(UPGRADEABLE_READER, Release);
10711215 atomic_with_ghost!(
0 commit comments