Skip to main content

ostd/sync/
rwlock.rs

1// SPDX-License-Identifier: MPL-2.0
2#[cfg(feature = "irc11")]
3use vstd::thread_view::Objective;
4use vstd::{
5    atomic_ghost::*,
6    cell::{self, CellId, pcell::*},
7    prelude::*,
8    resource::Loc,
9};
10use vstd_extra::{
11    prelude::*,
12    resource::{
13        self,
14        ghost_resource::{count_auth::*, count_ghost::*, csum::*, excl::*},
15    },
16    sum::*,
17};
18
19use alloc::sync::Arc;
20use core::char::MAX;
21use core::{
22    cell::UnsafeCell,
23    fmt,
24    marker::PhantomData,
25    ops::{Deref, DerefMut},
26    sync::atomic::{
27        // AtomicUsize,
28        Ordering::{AcqRel, Acquire, Relaxed, Release},
29    },
30};
31
32use super::{
33    PreemptDisabled,
34    guard::{GuardTransfer, SpinGuardian},
35};
36
37verus! {
38
39/// The token reserved in the lock when the write permission is given out.
40type NoPerm<T> = EmptyCount<PointsTo<T>>;
41
42/// Half of the permission for read access, one for `RwLockUpgradeableGuard` and the other for all `RwLockReadGuard`s.
43type HalfPerm<T> = Count<PointsTo<T>>;
44
45/// The permission for read access can be further split into `MAX_READER` pieces.
46type ReadPerm<T> = (HalfPerm<T>, OneLeftKnowledge<HalfPerm<T>, NoPerm<T>, 3>);
47
48tracked struct RwPerms<T> {
49    /// This token tracks whether the write permission is given out. If it is `Left`, it stores the knowledge that
50    /// there are active readers because the existence of `HalfPerm` resource for read access.
51    /// If it is `Right`, we know there is an active writer and there is no active reader, because there is a `NoPerm`
52    /// indicating the absence of `PointsTo<T>`.
53    core_token: SumResource<HalfPerm<T>, NoPerm<T>, 3>,
54    /// The permission to retract a `READER` count. Its total quantity tracks the gap between
55    /// the number of `try_read` increments recorded in the lock atomic and the number of active
56    /// `RwLockReadGuard`s (created and ongoing creation that will succeed) represented by `read_guard_token`.
57    /// It can be splited up to `MAX_READER_MASK` pieces,
58    /// which allows at most `MAX_READER_MASK - 1` `try_read` attempts that will fail to acquire the lock.
59    read_retract_token: TokenResource<MAX_READER_MASK>,
60    /// The permission to retract the set of `UPGRADEABLE_READER` bit.
61    upread_retract_token: Option<UniqueToken>,
62    /// Tracks whether there is a live `RwLockUpgradeableGuard`, also stores half of the permission for read access.
63    upreader_guard_token: Option<OneLeftOwner<HalfPerm<T>, NoPerm<T>, 3>>,
64    /// Tracks the remaining read permissions, or an empty state while a writer owns the resource.
65    read_guard_token: CountResource<ReadPerm<T>, MAX_READER>,
66}
67
68#[cfg(feature = "irc11")]
69unsafe impl<T> Objective for RwPerms<T> {
70
71}
72
73ghost struct RwId {
74    core_token_id: Loc,
75    frac_id: Loc,
76    read_retract_token_id: Loc,
77    upread_retract_token_id: Loc,
78    read_guard_token_id: Loc,
79}
80
81/// The number of `try_read` operations recorded in the lock atomic (created and ongoing) can never reach `2*MAX_READER` to avoid overflow.
82/// **NOTE**: We *ASSUME* this property always holds without any proof. We believe this is true in practice because:
83/// - More than `2^61` `try_read` operations are required to trigger the overflow concurrently, which is absurd in real world scenarios.
84/// - If one tries to create a huge number (more than `2*MAX_READER`) of `RwLockReadGuard`s in a loop with `mem::forget`, it will take years and
85/// will be prevented by the `MAX_READER` check.
86pub closed spec fn no_max_reader_overflow(v: usize) -> bool {
87    v & MAX_READER_MASK < MAX_READER_MASK
88}
89
90struct_with_invariants! {
91/// A spin lock that provides data access to either one writer or many readers.
92///
93/// # Overview
94///
95/// This lock allows for multiple readers, or at most one writer to access
96/// at any point in time. The writer of this lock has exclusive access to
97/// modify the underlying data, while the readers are allowed shared and
98/// read-only access.
99///
100/// The writing and reading portions cannot be active simultaneously, when
101/// one portion is in progress, the other portion will spin-wait. This is
102/// suitable for scenarios where the lock is expected to be held for short
103/// periods of time, and the overhead of context switching is higher than
104/// the cost of spinning.
105///
106/// In addition to traditional read and write locks, this implementation
107/// provides the upgradeable read lock (`upread lock`). The `upread lock`
108/// can be upgraded to write locks atomically, useful in scenarios
109/// where a decision to write is made after reading.
110///
111/// The type parameter `T` represents the data that this lock is protecting.
112/// It is necessary for `T` to satisfy [`Send`] to be shared across tasks and
113/// [`Sync`] to permit concurrent access via readers. The [`Deref`] method (and
114/// [`DerefMut`] for the writer) is implemented for the RAII guards returned
115/// by the locking methods, which allows for the access to the protected data
116/// while the lock is held.
117///
118/// # Usage
119/// The lock can be used in scenarios where data needs to be read frequently
120/// but written to occasionally.
121///
122/// Use `upread lock` in scenarios where related checking is performed before
123/// modification to effectively avoid deadlocks and improve efficiency.
124///
125/// This lock should not be used in scenarios where lock-holding times are
126/// long as it can lead to CPU resource wastage due to spinning.
127///
128/// # About Guard
129///
130/// See the comments of [`SpinLock`].
131///
132/// # Examples
133///
134/// ```
135/// use ostd::sync::RwLock;
136///
137/// let lock = RwLock::new(5)
138///
139/// // many read locks can be held at once
140/// {
141///     let r1 = lock.read();
142///     let r2 = lock.read();
143///     assert_eq!(*r1, 5);
144///     assert_eq!(*r2, 5);
145///
146///     // Upgradeable read lock can share access to data with read locks
147///     let r3 = lock.upread();
148///     assert_eq!(*r3, 5);
149///     drop(r1);
150///     drop(r2);
151///     // read locks are dropped at this point
152///
153///     // An upread lock can only be upgraded successfully after all the
154///     // read locks are released, otherwise it will spin-wait.
155///     let mut w1 = r3.upgrade();
156///     *w1 += 1;
157///     assert_eq!(*w1, 6);
158/// }   // upread lock are dropped at this point
159///
160/// {
161///     // Only one write lock can be held at a time
162///     let mut w2 = lock.write();
163///     *w2 += 1;
164///     assert_eq!(*w2, 7);
165/// }   // write lock is dropped at this point
166/// ```
167///
168/// [`SpinLock`]: super::SpinLock
169pub struct RwLock<T  /* : ?Sized*/ , Guard /* = PreemptDisabled*/ > {
170    guard: PhantomData<Guard>,
171    /// The internal representation of the lock state is as follows:
172    /// - **Bit 63:** Writer lock.
173    /// - **Bit 62:** Upgradeable reader lock.
174    /// - **Bit 61:** Indicates if an upgradeable reader is being upgraded.
175    /// - **Bits 60-0:** Reader lock count.
176    lock: AtomicUsize<_, RwPerms<T>,_>,
177    // val: UnsafeCell<T>,
178    val: PCell<T>,
179    ghost_id: Ghost<RwId>,
180}
181
182/// This invariant holds at any time, i.e. not violated during any method execution.
183closed spec fn wf(self) -> bool {
184    invariant on lock with (val, guard, ghost_id) is (v: usize, g: RwPerms<T>) {
185        // BITS VALUE
186        let has_writer_bit: bool = (v & WRITER) != 0;
187        let has_upgrade_bit: bool = (v & UPGRADEABLE_READER) != 0;
188        let has_max_reader_bit: bool = (v & MAX_READER) != 0;
189        // The total number of `try_read` attempts recorded in the lock atomic, including created `RwLockReadGuard`s
190        // and those who are trying, no matter they will succeed or fail.
191        let total_reader_bits: int = (v & MAX_READER_MASK) as int;
192        // The clamped value represented in the counter bits. This counts the maximum number of active `RwLockReadGuard`s.
193        // NOTE: This does not mean there are actually this number of active `RwLockReadGuard`s. The actual number of successfully
194        // created/creating `RwLockReadGuard`s can be smaller than this number, because previously created `RwLockReadGuard`s may be dropped.
195        let reader_bits: int = if has_max_reader_bit { MAX_READER as int } else { (v & READER_MASK) as int };
196
197        // ACTUAL NUMBER OF ACTIVE GUARDS.
198        // The number is tracked by the ghost resources remained in the lock.
199        // By active, we mean from the perspective the lock, the permissions for these guards are given out.
200        // The actual guards may be still being created, but they must be successfully created finally.
201        // This invariant maintains the consistency between the ghost resources and the lock atomic value.
202
203        // Whether there is an active writer
204        let active_writer: bool = g.core_token.is_right();
205        // The number of active `RwLockUpgradeableGuard`, which can only be 0 or 1.
206        let active_upgrade_guard: bool = !active_writer && g.upreader_guard_token is None;
207        // The number of active `RwLockReadGuard`s.
208        let active_read_guards: int = if g.read_guard_token.is_resource_vacant() {
209            0
210        } else {
211            MAX_READER - g.read_guard_token.frac()
212        };
213        // The first `try_upread` that fails, which has not returned yet.
214        let pending_failed_upread_attempt: bool = g.upread_retract_token is None;
215        // The number of `try_read` attempts that will fail.
216        let failed_reader_attempts: int = MAX_READER_MASK - g.read_retract_token.frac();
217
218        &&& if g.core_token.is_left() {
219            let resource = g.read_guard_token.resource();
220            let read_half_cell_perm = resource.0;
221            let mode_knowledge = resource.1;
222            &&& !g.read_guard_token.is_resource_vacant()
223            &&& mode_knowledge.id() == ghost_id@.core_token_id
224            &&& read_half_cell_perm.id() == ghost_id@.frac_id
225            &&& read_half_cell_perm.resource().id() == val.id()
226            &&& read_half_cell_perm.frac() == 1
227        } else {
228            &&& g.upreader_guard_token is None
229            &&& g.read_guard_token.is_resource_vacant()
230        }
231        // The `UPGRADEABLE_READER` bit is set iff there is an active `RwLockUpgradeableGuard` or a pending failed `try_upread` attempt.
232        &&& has_upgrade_bit <==> (active_upgrade_guard || pending_failed_upread_attempt)
233        // An active `RwLockUpgradeableGuard` cannot coexist with a pending failed `try_upread` attempt.
234        &&& !(active_upgrade_guard && pending_failed_upread_attempt)
235        // The `READER` bits count the number of all active read guards and pending failed `try_read` attempts.
236        &&& total_reader_bits == active_read_guards + failed_reader_attempts
237        // There is an active `RwLockWriteGuard` iff the `WRITER` bit is set.
238        &&& active_writer <==> has_writer_bit
239        // The number of active `RwLockReadGaurd`s is less than or equal to the `READER` bits.
240        &&& 0 <= active_read_guards <= reader_bits <= total_reader_bits
241        // The core invariant of `RwLock`: there are no simultaneous active writers and readers.
242        &&& !(active_writer && (active_read_guards + if active_upgrade_guard { 1int } else { 0 }) > 0)
243        &&& g.core_token.id() == ghost_id@.core_token_id
244        &&& g.core_token.wf()
245        &&& g.core_token.is_left() ==> {
246            &&& !g.core_token.is_resource_owner()
247            &&& g.core_token.frac() == 1
248        }
249        &&& g.core_token.is_right() ==> {
250            let empty = g.core_token.resource_right();
251            &&& empty.id() == ghost_id@.frac_id
252            &&& g.core_token.frac() == 2
253            &&& g.core_token.has_resource()
254        }
255        &&& g.read_retract_token.wf()
256        &&& g.read_retract_token.id() == ghost_id@.read_retract_token_id
257        &&& g.upread_retract_token is Some ==>
258            {
259                let token = g.upread_retract_token->0;
260                &&& token.wf()
261                &&& token.id() == ghost_id@.upread_retract_token_id
262            }
263        &&& g.upreader_guard_token is Some ==> {
264            let token = g.upreader_guard_token->0;
265            wf_upgradeable_guard_token(ghost_id@.core_token_id, ghost_id@.frac_id, val.id(), token)
266        }
267        &&& g.read_guard_token.wf()
268        &&& g.read_guard_token.id() == ghost_id@.read_guard_token_id
269    }
270}
271
272}
273
274const READER: usize = 1;
275
276const WRITER: usize = 1 << (usize::BITS - 1);
277
278const UPGRADEABLE_READER: usize = 1 << (usize::BITS - 2);
279
280const BEING_UPGRADED: usize = 1 << (usize::BITS - 3);
281
282/// This bit is reserved as an overflow sentinel.
283/// We intentionally cap read guards before counter growth can affect
284/// `BEING_UPGRADED` / `UPGRADEABLE_READER` / `WRITER` bits.
285/// This is defense-in-depth with no extra runtime cost.
286///
287/// This follows the same strategy as Rust std's `Arc`,
288/// which uses `isize::MAX` as a sentinel to prevent its reference count
289/// from overflowing into values that could compromise safety.
290///
291/// On 64-bit platforms (the only targets Asterinas supports),
292/// a counter overflow is not a practical concern:
293/// incrementing one-by-one from zero to `MAX_READER` (2^60)
294/// would take hundreds of years even at billions of increments per second.
295/// Nevertheless, this sentinel provides an extra layer of safety at no runtime cost.
296const MAX_READER: usize = 1 << (usize::BITS - 4);
297
298/// Used only in verification. Excluding the `MAX_READER` bit.
299const READER_MASK: usize = usize::MAX >> 4;
300
301/// Used only in verification. Including the `MAX_READER` bit.
302const MAX_READER_MASK: usize = usize::MAX >> 3;
303
304impl<T, G> RwLock<T, G> {
305    /// Returns the unique [`CellId`](https://verus-lang.github.io/verus/verusdoc/vstd/cell/struct.CellId.html) of the internal `PCell<T>`.
306    pub closed spec fn cell_id(self) -> cell::CellId {
307        self.val.id()
308    }
309
310    pub closed spec fn core_token_id(self) -> Loc {
311        self.ghost_id@.core_token_id
312    }
313
314    pub closed spec fn frac_id(self) -> Loc {
315        self.ghost_id@.frac_id
316    }
317
318    pub closed spec fn upread_retract_token_id(self) -> Loc {
319        self.ghost_id@.upread_retract_token_id
320    }
321
322    pub closed spec fn read_guard_token_id(self) -> Loc {
323        self.ghost_id@.read_guard_token_id
324    }
325
326    /// Encapsulates the invariant described in the *Invariant* section of [`RwLock`].
327    #[verifier::type_invariant]
328    pub closed spec fn type_inv(self) -> bool {
329        self.wf()
330    }
331}
332
333closed spec fn wf_upgradeable_guard_token<T>(
334    core_token_id: Loc,
335    frac_id: Loc,
336    cell_id: CellId,
337    token: OneLeftOwner<HalfPerm<T>, NoPerm<T>, 3>,
338) -> bool {
339    let half_cell_perm = token.resource();
340    &&& token.id() == core_token_id
341    &&& half_cell_perm.id() == frac_id
342    &&& half_cell_perm.resource().id() == cell_id
343    &&& token.has_resource()
344    &&& half_cell_perm.frac() == 1
345    &&& half_cell_perm.has_authority()
346    &&& token.wf()
347}
348
349impl<T, G> RwLock<T, G> {
350    /// Creates a new spin-based read-write lock with an initial value.
351    pub const fn new(val: T) -> Self {
352        let (val, Tracked(perm)) = PCell::new(val);
353
354        // Proof code
355        proof {
356            lemma_consts_properties();
357        }
358        let tracked mut frac_perm = Count::<PointsTo<T>>::alloc(perm);
359        let tracked read_half_cell_perm = frac_perm.split(1int);
360        let ghost frac_id = frac_perm.id();
361        let tracked mut core_token = SumResource::alloc_left(frac_perm);
362        let tracked read_retract_token = TokenResource::<MAX_READER_MASK>::alloc(());
363        let tracked upread_retract_token = UniqueToken::alloc(());
364        let tracked upreader_guard_token = core_token.split_one_left_owner();
365        let tracked left_token = core_token.split_one_left_knowledge();
366        let tracked read_guard_token = CountResource::<ReadPerm<T>, MAX_READER>::alloc(
367            (read_half_cell_perm, left_token),
368        );
369        let ghost ghost_id = RwId {
370            frac_id,
371            core_token_id: core_token.id(),
372            upread_retract_token_id: upread_retract_token.id(),
373            read_retract_token_id: read_retract_token.id(),
374            read_guard_token_id: read_guard_token.id(),
375        };
376        let tracked perms = RwPerms {
377            core_token,
378            read_retract_token,
379            upread_retract_token: Some(upread_retract_token),
380            upreader_guard_token: Some(upreader_guard_token),
381            read_guard_token,
382        };
383
384        Self {
385            guard: PhantomData,
386            //lock: AtomicUsize::new(0),
387            lock: AtomicUsize::new(Ghost((val, PhantomData, Ghost(ghost_id))), 0, Tracked(perms)),
388            //val: UnsafeCell::new(val),
389            val: val,
390            ghost_id: Ghost(ghost_id),
391        }
392    }
393}
394
395#[verus_verify]
396impl<T  /*: ?Sized*/ , G: SpinGuardian> RwLock<T, G> {
397    /// Acquires a read lock and spin-wait until it can be acquired.
398    ///
399    /// The calling thread will spin-wait until there are no writers or
400    /// upgrading upreaders present. There is no guarantee for the order
401    /// in which other readers or writers waiting simultaneously will
402    /// obtain the lock.
403    #[verifier::exec_allows_no_decreases_clause]
404    pub fn read(&self) -> RwLockReadGuard<'_, T, G> {
405        loop {
406            if let Some(readguard) = self.try_read() {
407                return readguard;
408            } else {
409                core::hint::spin_loop();
410            }
411        }
412    }
413
414    /// Acquires a write lock and spin-wait until it can be acquired.
415    ///
416    /// The calling thread will spin-wait until there are no other writers,
417    /// upreaders or readers present. There is no guarantee for the order
418    /// in which other readers or writers waiting simultaneously will
419    /// obtain the lock.
420    #[verifier::exec_allows_no_decreases_clause]
421    pub fn write(&self) -> RwLockWriteGuard<'_, T, G> {
422        loop {
423            if let Some(writeguard) = self.try_write() {
424                return writeguard;
425            } else {
426                core::hint::spin_loop();
427            }
428        }
429    }
430
431    /// Acquires an upreader and spin-wait until it can be acquired.
432    ///
433    /// The calling thread will spin-wait until there are no other writers,
434    /// or upreaders. There is no guarantee for the order in which other
435    /// readers or writers waiting simultaneously will obtain the lock.
436    ///
437    /// Upreader will not block new readers until it tries to upgrade. Upreader
438    /// and reader do not differ before invoking the upgrade method. However,
439    /// only one upreader can exist at any time to avoid deadlock in the
440    /// upgrade method.
441    #[verifier::exec_allows_no_decreases_clause]
442    pub fn upread(&self) -> RwLockUpgradeableGuard<'_, T, G> {
443        loop {
444            if let Some(guard) = self.try_upread() {
445                return guard;
446            } else {
447                core::hint::spin_loop();
448            }
449        }
450    }
451
452    /// Attempts to acquire a read lock.
453    ///
454    /// This function will never spin-wait and will return immediately.
455    #[verus_spec]
456    pub fn try_read(&self) -> Option<RwLockReadGuard<'_, T, G>> {
457        proof_decl!{
458            let tracked mut read_token: Option<Count<ReadPerm<T>,MAX_READER>> = None;
459            let tracked mut retract_read_token: Option<Token<MAX_READER_MASK>> = None;
460        }
461        proof!{
462            use_type_invariant(self);
463            lemma_consts_properties();
464        }
465        let guard = G::read_guard();
466
467        // let lock = self.lock.fetch_add(READER, Acquire);
468        let lock =
469            atomic_with_ghost!(
470            self.lock => fetch_add(READER);
471            update prev -> next;
472            ghost g => {
473                let prev_usize = prev as usize;
474                let next_usize = next as usize;
475                assume (no_max_reader_overflow(prev_usize));
476                lemma_consts_properties_value(prev_usize);
477                lemma_consts_properties_prev_next(prev_usize, next_usize);
478                if prev_usize & (WRITER | MAX_READER | BEING_UPGRADED) == 0 {
479                    read_token = Some(g.read_guard_token.split_one());
480                } else {
481                    retract_read_token = Some(g.read_retract_token.split_one());
482                }
483            }
484        );
485        if lock & (WRITER | MAX_READER | BEING_UPGRADED) == 0 {
486            Some(
487                RwLockReadGuard {
488                    guard,
489                    inner: self,
490                    tracked_token: Tracked(read_token.tracked_unwrap()),
491                },
492            )
493        } else {
494            // self.lock.fetch_sub(READER, Release);
495            atomic_with_ghost!(
496                self.lock => fetch_sub(READER);
497                update prev -> next;
498                ghost g => {
499                    let prev_usize = prev as usize;
500                    let next_usize = next as usize;
501                    lemma_consts_properties_value(next_usize);
502                    lemma_consts_properties_prev_next(prev_usize, next_usize);
503                    g.read_retract_token.combine(retract_read_token.tracked_unwrap());
504                }
505            );
506            None
507        }
508    }
509
510    /// Attempts to acquire a write lock.
511    ///
512    /// This function will never spin-wait and will return immediately.
513    #[verus_spec]
514    pub fn try_write(&self) -> Option<RwLockWriteGuard<'_, T, G>> {
515        proof_decl!{
516            let tracked mut guard_perm: Option<PointsTo<T>> = None;
517            let tracked mut guard_token: Option<OneRightKnowledge<HalfPerm<T>, NoPerm<T>, 3>> = None;
518        }
519        proof!{
520            use_type_invariant(self);
521            lemma_consts_properties();
522        }
523
524        let guard = G::guard();
525        // if self
526        //     .lock
527        //     .compare_exchange(0, WRITER, Acquire, Relaxed)
528        //     .is_ok()
529        if atomic_with_ghost!(
530            self.lock => compare_exchange(0, WRITER);
531            update prev -> next;
532            returning res;
533            ghost g => {
534                let prev_usize = prev as usize;
535                let next_usize = next as usize;
536                if res is Ok {
537                    // Retract the fractional permission for read access.
538                    let tracked read_resource = g.read_guard_token.take_resource();
539                    let tracked (read_half_cell_perm, left_token) = read_resource;
540                    g.core_token.join_one_left_knowledge(left_token);
541                    // Retract the fractional permission for upgradeable reader.
542                    let tracked upreader_guard_token = g.upreader_guard_token.tracked_take();
543                    g.core_token.join_one_left_owner(upreader_guard_token);
544                    // Combine the two halves of the permission for read access to get the full permission and give it out.
545                    let tracked mut pointsto = g.core_token.take_resource_left();
546                    pointsto.combine(read_half_cell_perm);
547                    let tracked (pointsto, empty) = pointsto.take_resource();
548                    guard_perm = Some(pointsto);
549                    g.core_token.change_to_right(empty);
550                    guard_token = Some(g.core_token.split_one_right_knowledge());
551                }
552            }
553        ).is_ok() {
554            Some(
555                RwLockWriteGuard {
556                    guard,
557                    inner: self,
558                    tracked_perm: Tracked(guard_perm.tracked_unwrap()),
559                    tracked_token: Tracked(guard_token.tracked_unwrap()),
560                },
561            )
562        } else {
563            None
564        }
565    }
566
567    /// Attempts to acquire an upread lock.
568    ///
569    /// This function will never spin-wait and will return immediately.
570    pub fn try_upread(&self) -> Option<RwLockUpgradeableGuard<'_, T, G>> {
571        proof_decl!{
572            let tracked mut upgrade_guard_token: Option<OneLeftOwner<HalfPerm<T>, NoPerm<T>, 3>> = None;
573            let tracked mut retract_upgrade_token: Option<UniqueToken> = None;
574        }
575        proof!{
576            use_type_invariant(self);
577            lemma_consts_properties();
578        }
579        let guard = G::guard();
580        // let lock = self.lock.fetch_or(UPGRADEABLE_READER, Acquire) & (WRITER | UPGRADEABLE_READER);
581        let lock =
582            atomic_with_ghost!(
583            self.lock => fetch_or(UPGRADEABLE_READER);
584            update prev -> next;
585            ghost g => {
586                lemma_consts_properties_value(prev);
587                lemma_consts_properties_prev_next(prev, next);
588                if prev & (WRITER | UPGRADEABLE_READER) == 0 {
589                    upgrade_guard_token = Some(g.upreader_guard_token.tracked_take());
590                }
591                else if prev & (WRITER | UPGRADEABLE_READER) == WRITER {
592                    retract_upgrade_token = Some(g.upread_retract_token.tracked_take());
593                }
594            }
595        )
596            & (WRITER | UPGRADEABLE_READER);
597        if lock == 0 {
598            return Some(
599                RwLockUpgradeableGuard {
600                    guard,
601                    inner: self,
602                    tracked_token: Tracked(upgrade_guard_token.tracked_unwrap()),
603                },
604            );
605        } else if lock == WRITER {
606            // self.lock.fetch_sub(UPGRADEABLE_READER, Release);
607            atomic_with_ghost!(
608                self.lock => fetch_sub(UPGRADEABLE_READER);
609                update prev -> next;
610                ghost g => {
611                    let prev_usize = prev as usize;
612                    let next_usize = next as usize;
613                    lemma_consts_properties_value(prev_usize);
614                    lemma_consts_properties_prev_next(prev_usize, next_usize);
615                    if g.upread_retract_token is Some {
616                        let tracked mut token = retract_upgrade_token.tracked_unwrap();
617                        token.validate_with_other(g.upread_retract_token.tracked_borrow());
618                    }
619                    else{
620                        g.upread_retract_token= retract_upgrade_token;
621                    }
622                }
623            );
624        }
625        None
626    }/*
627    /// Returns a mutable reference to the underlying data.
628    ///
629    /// This method is zero-cost: By holding a mutable reference to the lock, the compiler has
630    /// already statically guaranteed that access to the data is exclusive.
631    pub fn get_mut(&mut self) -> &mut T {
632        self.val.get_mut()
633    }
634
635    /// Returns a raw pointer to the underlying data.
636    ///
637    /// This method is safe, but it's up to the caller to ensure that access to the data behind it
638    /// is still safe.
639    pub(super) fn as_ptr(&self) -> *mut T {
640        self.val.get()
641    }*/
642
643}
644
645/* the trait `core::fmt::Debug` is not implemented for `vstd::cell::pcell::PCell<T>`
646impl<T: ?Sized + fmt::Debug, G> fmt::Debug for RwLock<T, G> {
647    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
648        fmt::Debug::fmt(&self.val, f)
649    }
650}*/
651
652// There can be more than one readers to get the `T`'s immutable reference,
653// so `T` must be `Sync` to guarantee the sharing safety.
654#[verifier::external]
655unsafe impl<T: Send, G> Send for RwLock<T, G> {
656
657}
658
659#[verifier::external]
660unsafe impl<T: Send + Sync, G> Sync for RwLock<T, G> {
661
662}
663
664// `G::Guard` and `G::ReadGuard` are `!Send` and `!Sync`, so are the guards.
665impl<T  /*: ?Sized*/ , G: SpinGuardian> !Send for RwLockWriteGuard<'_, T, G> {
666
667}
668
669impl<T, G: SpinGuardian> !Sync for RwLockWriteGuard<'_, T, G> {
670
671}
672
673impl<T  /*: ?Sized*/ , G: SpinGuardian> !Send for RwLockReadGuard<'_, T, G> {
674
675}
676
677impl<T, G: SpinGuardian> !Sync for RwLockReadGuard<'_, T, G> {
678
679}
680
681impl<T  /*: ?Sized*/ , G: SpinGuardian> !Send for RwLockUpgradeableGuard<'_, T, G> {
682
683}
684
685impl<T, G: SpinGuardian> !Sync for RwLockUpgradeableGuard<'_, T, G> {
686
687}
688
689/// A guard that provides immutable data access.
690#[verifier::reject_recursive_types(T)]
691#[verifier::reject_recursive_types(G)]
692#[clippy::has_significant_drop]
693#[must_use]
694#[verus_verify]
695pub struct RwLockReadGuard<'a, T  /*: ?Sized*/ , G: SpinGuardian> {
696    guard: G::ReadGuard,
697    inner: &'a RwLock<T, G>,
698    tracked_token: Tracked<Count<ReadPerm<T>, MAX_READER>>,
699}
700
701/*
702impl<T: ?Sized, G: SpinGuardian> AsAtomicModeGuard for RwLockReadGuard<'_, T, G> {
703    fn as_atomic_mode_guard(&self) -> &dyn crate::task::atomic_mode::InAtomicMode {
704        self.guard.as_atomic_mode_guard()
705    }
706}
707*/
708
709impl<'a, T, G: SpinGuardian> RwLockReadGuard<'a, T, G> {
710    #[verifier::type_invariant]
711    pub closed spec fn type_inv(self) -> bool {
712        let resource = self.tracked_token@.resource();
713        let read_half_cell_perm = resource.0;
714        let mode_knowledge = resource.1;
715        &&& self.inner.core_token_id() == mode_knowledge.id()
716        &&& self.inner.frac_id() == read_half_cell_perm.id()
717        &&& self.inner.cell_id() == read_half_cell_perm.resource().id()
718        &&& self.tracked_token@.id() == self.inner.read_guard_token_id()
719        &&& read_half_cell_perm.frac() == 1
720        &&& self.tracked_token@.frac() == 1
721    }
722
723    /// The value stored in the lock.
724    pub closed spec fn value(self) -> T {
725        *self.tracked_token@.resource().0.resource().value()
726    }
727
728    /// The value stored in the lock. It is an alias of `Self::value`.
729    pub open spec fn view(self) -> T {
730        self.value()
731    }
732}
733
734impl<T  /*: ?Sized*/ , G: SpinGuardian> Deref for RwLockReadGuard<'_, T, G> {
735    type Target = T;
736
737    #[verus_spec(returns self.view())]
738    fn deref(&self) -> &T {
739        proof!{
740            use_type_invariant(self);
741        }
742        // unsafe { &*self.inner.val.get() }
743        // The internal implementation of `PCell<T>::borrow` is exactly unsafe { &(*(*self.ucell).get()) },
744        // and here we verify that we have the permission to call `borrow`.
745        self.inner.val.borrow(
746            Tracked(self.tracked_token.borrow().tracked_borrow().0.tracked_borrow()),
747        )
748    }
749}
750
751/* impl<T: ?Sized, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian> Drop
752    for RwLockReadGuard_<T, R, G>
753{
754    fn drop(&mut self) {
755        self.inner.lock.fetch_sub(READER, Release);
756    }
757} */
758
759#[verus_verify]
760impl<T  /*: ?Sized*/ , G: SpinGuardian> RwLockReadGuard<'_, T, G> {
761    /// VERUS LIMITATION: We implement `drop` and call it manually because Verus's support for `Drop` is incomplete for now.
762    #[verus_spec]
763    fn drop(self) {
764        proof! {
765            use_type_invariant(&self);
766            use_type_invariant(self.inner);
767            lemma_consts_properties();
768        }
769        proof_decl! {
770            let tracked token = self.tracked_token.get();
771        }
772        // self.inner.lock.fetch_sub(READER, Release);
773        atomic_with_ghost!(
774            self.inner.lock => fetch_sub(READER);
775            update prev -> next;
776            ghost g => {
777                let prev_usize = prev as usize;
778                let next_usize = next as usize;
779                assume (no_max_reader_overflow(prev_usize));
780                lemma_consts_properties_value(next_usize);
781                lemma_consts_properties_prev_next(prev_usize, next_usize);
782                g.core_token.validate_with_one_left_knowledge(&token.tracked_borrow().1);
783                g.read_guard_token.combine(token);
784            }
785        );
786    }
787}
788
789/*
790impl<T: ?Sized + fmt::Debug, G: SpinGuardian> fmt::Debug for RwLockReadGuard<'_, T, G> {
791    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
792        fmt::Debug::fmt(&**self, f)
793    }
794}*/
795
796/// A guard that provides mutable data access.
797#[verifier::reject_recursive_types(T)]
798#[verifier::reject_recursive_types(G)]
799pub struct RwLockWriteGuard<'a, T  /*: ?Sized*/ , G: SpinGuardian> {
800    guard: G::Guard,
801    inner: &'a RwLock<T, G>,
802    /// Ghost permission for verification
803    tracked_perm: Tracked<PointsTo<T>>,
804    tracked_token: Tracked<OneRightKnowledge<HalfPerm<T>, NoPerm<T>, 3>>,
805}
806
807impl<'a, T, G: SpinGuardian> RwLockWriteGuard<'a, T, G> {
808    #[verifier::type_invariant]
809    spec fn type_inv(self) -> bool {
810        &&& self.inner.cell_id() == self.tracked_perm@.id()
811        &&& self.inner.core_token_id() == self.tracked_token@.id()
812    }
813
814    /// The value stored in the lock.
815    pub closed spec fn value(self) -> T {
816        *self.tracked_perm@.value()
817    }
818
819    /// The value stored in the lock. It is an alias of `Self::value`.
820    pub open spec fn view(self) -> T {
821        self.value()
822    }
823}
824
825/*
826impl<T: ?Sized, G: SpinGuardian> AsAtomicModeGuard for RwLockWriteGuard<'_, T, G> {
827    fn as_atomic_mode_guard(&self) -> &dyn crate::task::atomic_mode::InAtomicMode {
828        self.guard.as_atomic_mode_guard()
829    }
830}*/
831
832impl<T  /*: ?Sized*/ , G: SpinGuardian> Deref for RwLockWriteGuard<'_, T, G> {
833    type Target = T;
834
835    #[verus_spec(returns self.view())]
836    fn deref(&self) -> &T {
837        proof!{
838            use_type_invariant(self);
839        }
840        // unsafe { &*self.inner.val.get() }
841        // The internal implementation of `PCell<T>::borrow` is exactly unsafe { &(*(*self.ucell).get()) },
842        // and here we verify that we have the permission to call `borrow`.
843        self.inner.val.borrow(Tracked(self.tracked_perm.borrow()))
844    }
845}
846
847#[verus_verify]
848impl<T  /*: ?Sized*/ , G: SpinGuardian> DerefMut for RwLockWriteGuard<'_, T, G> {
849    #[verus_spec(ret =>
850        ensures
851            final(self).view() == *final(ret),
852            old(self).view() == *ret,
853    )]
854    fn deref_mut(&mut self) -> &mut Self::Target {
855        proof!{
856            use_type_invariant(&*self);
857        }
858        //unsafe { &mut *self.inner.val.get() }
859        self.inner.val.borrow_mut(Tracked(&mut *self.tracked_perm))
860    }
861}
862
863/*
864impl<T: ?Sized, G: SpinGuardian> Drop for RwLockWriteGuard<'_, T, G> {
865    fn drop(&mut self) {
866        self.inner.lock.fetch_and(!WRITER, Release);
867    }
868}*/
869
870impl<T  /*: ?Sized*/ , G: SpinGuardian> RwLockWriteGuard<'_, T, G> {
871    /// VERUS LIMITATION: We implement `drop` and call it manually because Verus's support for `Drop` is incomplete for now.
872    pub fn drop(self) {
873        proof!{
874            use_type_invariant(&self);
875            use_type_invariant(self.inner);
876            lemma_consts_properties();
877        }
878        proof_decl! {
879            let tracked mut perm = self.tracked_perm.get();
880            let tracked token = self.tracked_token.get();
881        }
882        //self.inner.lock.fetch_and(!WRITER, Release);
883        atomic_with_ghost!{
884            self.inner.lock => fetch_and(!WRITER);
885            update prev -> next;
886            ghost g => {
887                let prev_usize = prev as usize;
888                let next_usize = next as usize;
889                lemma_consts_properties_prev_next(prev_usize, next_usize);
890                lemma_consts_properties_value(next_usize);
891                g.core_token.validate_with_one_right_knowledge(&token);
892                g.core_token.join_one_right_knowledge(token);
893                let tracked empty = g.core_token.take_resource_right();
894                let tracked mut full = empty.put_resource(perm);
895                let tracked read_half_cell_perm = full.split(1int);
896                g.core_token.change_to_left(full);
897                let tracked upreader_guard_token = g.core_token.split_one_left_owner();
898                g.upreader_guard_token = Some(upreader_guard_token);
899                let tracked left_token = g.core_token.split_one_left_knowledge();
900                g.read_guard_token.put_resource((read_half_cell_perm, left_token));
901            }
902        };
903    }
904}
905
906/*
907impl<T: ?Sized + fmt::Debug, G: SpinGuardian> fmt::Debug for RwLockWriteGuard<'_, T, G> {
908    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
909        fmt::Debug::fmt(&**self, f)
910    }
911}*/
912
913/// A guard that provides immutable data access but can be atomically
914/// upgraded to [`RwLockWriteGuard`].
915#[verifier::reject_recursive_types(T)]
916#[verifier::reject_recursive_types(G)]
917pub struct RwLockUpgradeableGuard<'a, T  /*: ?Sized*/ , G: SpinGuardian> {
918    guard: G::Guard,
919    inner: &'a RwLock<T, G>,
920    tracked_token: Tracked<OneLeftOwner<HalfPerm<T>, NoPerm<T>, 3>>,
921}
922
923/*
924impl<T: ?Sized, G: SpinGuardian> AsAtomicModeGuard for RwLockUpgradeableGuard<'_, T, G> {
925    fn as_atomic_mode_guard(&self) -> &dyn crate::task::atomic_mode::InAtomicMode {
926        self.guard.as_atomic_mode_guard()
927    }
928}*/
929
930impl<'a, T, G: SpinGuardian> RwLockUpgradeableGuard<'a, T, G> {
931    #[verifier::type_invariant]
932    pub closed spec fn type_inv(self) -> bool {
933        wf_upgradeable_guard_token(
934            self.inner.core_token_id(),
935            self.inner.frac_id(),
936            self.inner.cell_id(),
937            self.tracked_token@,
938        )
939    }
940
941    /// The value stored in the lock.
942    pub closed spec fn value(self) -> T {
943        *self.tracked_token@.resource().resource().value()
944    }
945
946    /// The value stored in the lock. It is an alias of `Self::value`.
947    pub open spec fn view(self) -> T {
948        self.value()
949    }
950}
951
952impl<'a, T  /*: ?Sized*/ , G: SpinGuardian> RwLockUpgradeableGuard<'a, T, G> {
953    /// Upgrades this upread guard to a write guard atomically.
954    ///
955    /// After calling this method, subsequent readers will be blocked
956    /// while previous readers remain unaffected. The calling thread
957    /// will spin-wait until previous readers finish.
958    #[verifier::exec_allows_no_decreases_clause]
959    pub fn upgrade(mut self) -> RwLockWriteGuard<'a, T, G> {
960        proof! {
961            use_type_invariant(&self);
962            use_type_invariant(&self.inner);
963            lemma_consts_properties();
964        }
965        // self.inner.lock.fetch_or(BEING_UPGRADED, Acquire);
966        atomic_with_ghost!(
967            self.inner.lock => fetch_or(BEING_UPGRADED);
968            update prev -> next;
969            ghost g => {
970                lemma_consts_properties_prev_next(prev, next);
971            }
972        );
973        loop {
974            self =
975            match self.try_upgrade() {
976                Ok(guard) => return guard,
977                Err(e) => e,
978            };
979        }
980    }
981
982    // [FIXED] BUG FOUND BY FV: deadlock. https://github.com/asterinas/asterinas/pull/3007
983    /// Attempts to upgrade this upread guard to a write guard atomically.
984    ///
985    /// This function will never spin-wait and will return immediately.
986    ///
987    /// This function is not exposed publicly because the `BEING_UPGRADED` bit
988    /// is set only in [`Self::upgrade`].
989    fn try_upgrade(mut self) -> Result<RwLockWriteGuard<'a, T, G>, Self> {
990        proof! {
991            use_type_invariant(&self);
992            use_type_invariant(self.inner);
993            lemma_consts_properties();
994        }
995        proof_decl! {
996            let tracked mut upread_guard_token = self.tracked_token.get();
997            let tracked mut write_perm: Option<PointsTo<T>> = None;
998            let tracked mut err_upread_guard_token: Option<OneLeftOwner<HalfPerm<T>, NoPerm<T>, 3>> = None;
999            let tracked mut retract_upgrade_token: Option<UniqueToken> = None;
1000            let tracked mut write_guard_token = None;
1001        }
1002
1003        // let res = self.inner.lock.compare_exchange(
1004        //     UPGRADEABLE_READER | BEING_UPGRADED,
1005        //     WRITER | UPGRADEABLE_READER,
1006        //     AcqRel,
1007        //     Relaxed,
1008        // );
1009        let res =
1010            atomic_with_ghost!(
1011            self.inner.lock => compare_exchange(UPGRADEABLE_READER | BEING_UPGRADED, WRITER | UPGRADEABLE_READER);
1012            update prev -> next;
1013            returning res;
1014            ghost g => {
1015                lemma_consts_properties_prev_next(prev, next);
1016                if res is Ok {
1017                    g.core_token.validate_with_one_left_owner(&upread_guard_token);
1018                    if g.upreader_guard_token is Some {
1019                        upread_guard_token.validate_with_one_left_owner(g.upreader_guard_token.tracked_borrow());
1020                    }
1021                    g.core_token.join_one_left_owner(upread_guard_token);
1022                    let tracked read_resource = g.read_guard_token.take_resource();
1023                    let tracked (read_half_cell_perm, left_token) = read_resource;
1024                    g.core_token.join_one_left_knowledge(left_token);
1025                    let tracked mut pointsto = g.core_token.take_resource_left();
1026                    pointsto.combine(read_half_cell_perm);
1027                    let tracked (pointsto, empty) = pointsto.take_resource();
1028                    write_perm = Some(pointsto);
1029                    g.core_token.change_to_right(empty);
1030                    write_guard_token = Some(g.core_token.split_one_right_knowledge());
1031                    retract_upgrade_token = Some(g.upread_retract_token.tracked_take());
1032                } else {
1033                    err_upread_guard_token = Some(upread_guard_token);
1034                }
1035            }
1036        );
1037        if res.is_ok() {
1038            let guard = self.guard.transfer_to();
1039            let inner = self.inner;
1040            // drop(self);
1041            atomic_with_ghost!(
1042                inner.lock => fetch_sub(UPGRADEABLE_READER);
1043                update prev -> next;
1044                ghost g => {
1045                    let prev_usize = prev as usize;
1046                    let next_usize = next as usize;
1047                    lemma_consts_properties_value(prev_usize);
1048                    lemma_consts_properties_prev_next(prev_usize, next_usize);
1049                    let tracked mut token = retract_upgrade_token.tracked_unwrap();
1050                    if g.upread_retract_token is Some {
1051                        token.validate_with_other(g.upread_retract_token.tracked_borrow());
1052                    }
1053                    g.upread_retract_token = Some(token);
1054                }
1055            );
1056            Ok(
1057                RwLockWriteGuard {
1058                    guard,
1059                    inner,
1060                    tracked_perm: Tracked(write_perm.tracked_unwrap()),
1061                    tracked_token: Tracked(write_guard_token.tracked_unwrap()),
1062                },
1063            )
1064        } else {
1065            Err(
1066                RwLockUpgradeableGuard {
1067                    guard: self.guard,
1068                    inner: self.inner,
1069                    tracked_token: Tracked(err_upread_guard_token.tracked_unwrap()),
1070                },
1071            )
1072        }
1073    }
1074}
1075
1076impl<T  /*: ?Sized*/ , G: SpinGuardian> Deref for RwLockUpgradeableGuard<'_, T, G> {
1077    type Target = T;
1078
1079    #[verus_spec(returns self.view())]
1080    fn deref(&self) -> &T {
1081        proof!{
1082            use_type_invariant(self);
1083        }
1084        // unsafe { &*self.inner.val.get() }
1085        // The internal implementation of `PCell<T>::borrow` is exactly unsafe { &(*(*self.ucell).get()) },
1086        // and here we verify that we have the permission to call `borrow`.
1087        self.inner.val.borrow(
1088            Tracked(self.tracked_token.borrow().tracked_borrow().tracked_borrow()),
1089        )
1090    }
1091}
1092
1093/*
1094impl<T: ?Sized, G: SpinGuardian> Drop for RwLockUpgradeableGuard<'_, T, G> {
1095    fn drop(&mut self) {
1096        self.inner.lock.fetch_sub(UPGRADEABLE_READER, Release);
1097    }
1098}*/
1099
1100impl<T  /*: ?Sized*/ , G: SpinGuardian> RwLockUpgradeableGuard<'_, T, G> {
1101    /// VERUS LIMITATION: We implement `drop` and call it manually because Verus's support for `Drop` is incomplete for now.
1102    pub fn drop(self) {
1103        proof! {
1104            use_type_invariant(&self);
1105            use_type_invariant(self.inner);
1106            lemma_consts_properties();
1107        }
1108        proof_decl!{
1109            let tracked guard_token = self.tracked_token.get();
1110        }
1111        //self.inner.lock.fetch_sub(UPGRADEABLE_READER, Release);
1112        atomic_with_ghost!(
1113            self.inner.lock => fetch_sub(UPGRADEABLE_READER);
1114            update prev -> next;
1115            ghost g => {
1116                let prev_usize = prev as usize;
1117                let next_usize = next as usize;
1118                lemma_consts_properties_value(prev_usize);
1119                lemma_consts_properties_prev_next(prev_usize, next_usize);
1120                g.core_token.validate_with_one_left_owner(&guard_token);
1121                if g.upreader_guard_token is Some {
1122                    guard_token.validate_with_one_left_owner(g.upreader_guard_token.tracked_borrow());
1123                    assert(false);
1124                } else {
1125                    g.upreader_guard_token= Some(guard_token);
1126                }
1127            }
1128        );
1129    }
1130}
1131
1132/*
1133impl<T: ?Sized + fmt::Debug, G: SpinGuardian> fmt::Debug for RwLockUpgradeableGuard<'_, T, G> {
1134    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1135        fmt::Debug::fmt(&**self, f)
1136    }
1137}
1138*/
1139
1140#[verifier::bit_vector]
1141proof fn lemma_consts_properties()
1142    ensures
1143        0 & WRITER == 0,
1144        0 & UPGRADEABLE_READER == 0,
1145        0 & BEING_UPGRADED == 0,
1146        0 & READER_MASK == 0,
1147        0 & MAX_READER_MASK == 0,
1148        0 & MAX_READER == 0,
1149        0 & READER == 0,
1150        WRITER == 0x8000_0000_0000_0000,
1151        UPGRADEABLE_READER == 0x4000_0000_0000_0000,
1152        BEING_UPGRADED == 0x2000_0000_0000_0000,
1153        READER_MASK == 0x0FFF_FFFF_FFFF_FFFF,
1154        MAX_READER_MASK == 0x1FFF_FFFF_FFFF_FFFF,
1155        MAX_READER == 0x1000_0000_0000_0000,
1156        WRITER & WRITER == WRITER,
1157        WRITER & !WRITER == 0,
1158        WRITER & BEING_UPGRADED == 0,
1159        WRITER & READER_MASK == 0,
1160        WRITER & MAX_READER_MASK == 0,
1161        WRITER & MAX_READER == 0,
1162        WRITER & UPGRADEABLE_READER == 0,
1163        BEING_UPGRADED & WRITER == 0,
1164        BEING_UPGRADED & UPGRADEABLE_READER == 0,
1165        UPGRADEABLE_READER & BEING_UPGRADED == 0,
1166        UPGRADEABLE_READER & READER_MASK == 0,
1167        UPGRADEABLE_READER & MAX_READER_MASK == 0,
1168        UPGRADEABLE_READER & MAX_READER == 0,
1169        BEING_UPGRADED & READER_MASK == 0,
1170        BEING_UPGRADED & MAX_READER_MASK == 0,
1171        BEING_UPGRADED & MAX_READER == 0,
1172        (UPGRADEABLE_READER | BEING_UPGRADED) & WRITER == 0,
1173        (UPGRADEABLE_READER | BEING_UPGRADED) & UPGRADEABLE_READER == UPGRADEABLE_READER,
1174        (UPGRADEABLE_READER | BEING_UPGRADED) & BEING_UPGRADED == BEING_UPGRADED,
1175        (UPGRADEABLE_READER | BEING_UPGRADED) & READER_MASK == 0,
1176        (UPGRADEABLE_READER | BEING_UPGRADED) & MAX_READER_MASK == 0,
1177        (UPGRADEABLE_READER | BEING_UPGRADED) & MAX_READER == 0,
1178        (WRITER | UPGRADEABLE_READER) & WRITER == WRITER,
1179        (WRITER | UPGRADEABLE_READER) & UPGRADEABLE_READER == UPGRADEABLE_READER,
1180        (WRITER | UPGRADEABLE_READER) & BEING_UPGRADED == 0,
1181        (WRITER | UPGRADEABLE_READER) & READER_MASK == 0,
1182        (WRITER | UPGRADEABLE_READER) & MAX_READER_MASK == 0,
1183        (WRITER | UPGRADEABLE_READER) & MAX_READER == 0,
1184{
1185}
1186
1187#[verifier::bit_vector]
1188proof fn lemma_consts_properties_value(prev: usize)
1189    ensures
1190        no_max_reader_overflow(prev) ==> prev + READER <= usize::MAX,
1191        prev & (WRITER | MAX_READER | BEING_UPGRADED) == 0 ==> {
1192            &&& prev & WRITER == 0
1193            &&& prev & BEING_UPGRADED == 0
1194            &&& prev & MAX_READER == 0
1195        },
1196        prev & (WRITER | UPGRADEABLE_READER) == 0 ==> {
1197            &&& prev & WRITER == 0
1198            &&& prev & UPGRADEABLE_READER == 0
1199        },
1200        prev & MAX_READER == 0 ==> prev & READER_MASK == prev & MAX_READER_MASK,
1201        prev & MAX_READER != 0 ==> prev & MAX_READER_MASK >= MAX_READER,
1202        prev & (WRITER | UPGRADEABLE_READER) == WRITER ==> {
1203            &&& prev & UPGRADEABLE_READER == 0
1204            &&& prev & WRITER == WRITER
1205        },
1206        prev & UPGRADEABLE_READER != 0 ==> prev >= UPGRADEABLE_READER,
1207        prev & UPGRADEABLE_READER == 0 ==> {
1208            ||| prev & (WRITER | UPGRADEABLE_READER) == 0
1209            ||| prev & (WRITER | UPGRADEABLE_READER) == WRITER
1210        },
1211{
1212}
1213
1214#[verifier::bit_vector]
1215proof fn lemma_consts_properties_prev_next(prev: usize, next: usize)
1216    ensures
1217        prev & READER_MASK < MAX_READER,
1218        next == prev | UPGRADEABLE_READER ==> {
1219            &&& next & UPGRADEABLE_READER != 0
1220            &&& next & WRITER == prev & WRITER
1221            &&& next & READER_MASK == prev & READER_MASK
1222            &&& next & MAX_READER_MASK == prev & MAX_READER_MASK
1223            &&& next & MAX_READER == prev & MAX_READER
1224            &&& next & BEING_UPGRADED == prev & BEING_UPGRADED
1225        },
1226        next == prev | BEING_UPGRADED ==> {
1227            &&& next & BEING_UPGRADED != 0
1228            &&& next & WRITER == prev & WRITER
1229            &&& next & UPGRADEABLE_READER == prev & UPGRADEABLE_READER
1230            &&& next & READER_MASK == prev & READER_MASK
1231            &&& next & MAX_READER_MASK == prev & MAX_READER_MASK
1232            &&& next & MAX_READER == prev & MAX_READER
1233        },
1234        next == prev - UPGRADEABLE_READER && prev & UPGRADEABLE_READER != 0 ==> {
1235            &&& next & UPGRADEABLE_READER == 0
1236            &&& next & WRITER == prev & WRITER
1237            &&& next & READER_MASK == prev & READER_MASK
1238            &&& next & MAX_READER_MASK == prev & MAX_READER_MASK
1239            &&& next & MAX_READER == prev & MAX_READER
1240            &&& next & BEING_UPGRADED == prev & BEING_UPGRADED
1241        },
1242        next == prev - READER && prev & READER_MASK != 0 ==> {
1243            &&& next & READER_MASK == (prev & READER_MASK) - READER
1244            &&& next & MAX_READER_MASK == (prev & MAX_READER_MASK) - READER
1245            &&& next & UPGRADEABLE_READER == prev & UPGRADEABLE_READER
1246            &&& next & WRITER == prev & WRITER
1247            &&& next & MAX_READER == prev & MAX_READER
1248            &&& next & BEING_UPGRADED == prev & BEING_UPGRADED
1249        },
1250        next == prev - READER && prev & MAX_READER_MASK != 0 ==> {
1251            &&& next & MAX_READER_MASK == (prev & MAX_READER_MASK) - READER
1252            &&& next & UPGRADEABLE_READER == prev & UPGRADEABLE_READER
1253            &&& next & WRITER == prev & WRITER
1254            &&& next & BEING_UPGRADED == prev & BEING_UPGRADED
1255        },
1256        next == prev + READER && no_max_reader_overflow(prev) ==> {
1257            &&& next & READER_MASK == if (prev & READER_MASK) + READER == MAX_READER {
1258                0
1259            } else {
1260                (prev & READER_MASK) + READER
1261            }
1262            &&& next & MAX_READER_MASK == (prev & MAX_READER_MASK) + READER
1263            &&& next & UPGRADEABLE_READER == prev & UPGRADEABLE_READER
1264            &&& next & WRITER == prev & WRITER
1265            &&& next & MAX_READER == if (prev & READER_MASK) + READER == MAX_READER {
1266                MAX_READER
1267            } else {
1268                prev & MAX_READER
1269            }
1270            &&& next & BEING_UPGRADED == prev & BEING_UPGRADED
1271        },
1272        next == prev & !WRITER ==> {
1273            &&& next & WRITER == 0
1274            &&& next & UPGRADEABLE_READER == prev & UPGRADEABLE_READER
1275            &&& next & READER_MASK == prev & READER_MASK
1276            &&& next & MAX_READER_MASK == prev & MAX_READER_MASK
1277            &&& next & MAX_READER == prev & MAX_READER
1278            &&& next & BEING_UPGRADED == prev & BEING_UPGRADED
1279        },
1280{
1281}
1282
1283} // verus!