Skip to content

Commit 0b1c8f7

Browse files
committed
prove: try_upgrade and upgrade
1 parent b5f3dba commit 0b1c8f7

1 file changed

Lines changed: 174 additions & 14 deletions

File tree

ostd/src/sync/rwlock.rs

Lines changed: 174 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ tracked struct RwPerms<T> {
7979
}
8080

8181
ghost struct RwId {
82+
cell_perm_id: Loc,
8283
upgrade_retract_token_id: Loc,
8384
read_retract_token_id: Loc,
8485
}
@@ -216,12 +217,13 @@ closed spec fn wf(self) -> bool {
216217
} else {
217218
2int
218219
}
220+
&&& (v & UPGRADEABLE_READER) != 0usize && (v & WRITER) == 0usize ==> g.cell_perm is Some
221+
&&& g.cell_perm is Some ==> g.cell_perm->Some_0.id() == v_id@.cell_perm_id
219222
&&& 0 <= successful_read_guards <= reader_count <= total_reader_attempts
220223
&&& 1 <= g.read_retract_token.frac() <= V_MAX_READ_RETRACT_FRACS
221224
&&& match g.cell_perm {
222225
None => {
223226
&&& has_writer
224-
&&& (v & BEING_UPGRADED) == 0usize
225227
}
226228
Some(perm) => {
227229
&&& !has_writer
@@ -257,6 +259,10 @@ impl<T, G> RwLock<T, G> {
257259
self.val.id()
258260
}
259261

262+
pub closed spec fn cell_perm_id(self) -> Loc {
263+
self.v_id@.cell_perm_id
264+
}
265+
260266
pub closed spec fn upgrade_retract_token_id(self) -> Loc {
261267
self.v_id@.upgrade_retract_token_id
262268
}
@@ -846,6 +852,7 @@ verus! {
846852
impl<T, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian> RwLockReadGuard_<T, R, G> {
847853
#[verifier::type_invariant]
848854
pub closed spec fn type_inv(self) -> bool {
855+
&&& self.inner.deref_spec().cell_perm_id() == self.v_perm@.id()
849856
&&& self.inner.deref_spec().cell_id() == self.v_perm@.resource().id()
850857
&&& self.v_perm@.frac() == 1
851858
}
@@ -1043,13 +1050,13 @@ verus! {
10431050
impl<T, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian> RwLockUpgradeableGuard_<T, R, G> {
10441051
#[verifier::type_invariant]
10451052
pub closed spec fn type_inv(self) -> bool {
1053+
&&& self.inner.deref_spec().cell_perm_id() == self.v_perm@.id()
10461054
&&& self.inner.deref_spec().cell_id() == self.v_perm@.resource().id()
10471055
&&& self.v_perm@.frac() == 1
10481056
}
10491057
}
10501058

1051-
} // verus!
1052-
1059+
#[verus_verify]
10531060
impl<T /*: ?Sized*/, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian>
10541061
RwLockUpgradeableGuard_<T, R, G>
10551062
{
@@ -1058,13 +1065,48 @@ impl<T /*: ?Sized*/, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian>
10581065
/// After calling this method, subsequent readers will be blocked
10591066
/// while previous readers remain unaffected. The calling thread
10601067
/// will spin-wait until previous readers finish.
1061-
#[verifier::external_body]
1068+
#[verus_spec]
1069+
#[verifier::exec_allows_no_decreases_clause]
10621070
pub fn upgrade(self) -> RwLockWriteGuard_<T, R, G> {
10631071
let mut this = self;
1072+
let lock = this.inner.deref();
1073+
proof! {
1074+
use_type_invariant(&this);
1075+
use_type_invariant(lock);
1076+
lemma_consts_properties();
1077+
}
10641078
// self.inner.lock.fetch_or(BEING_UPGRADED, Acquire);
10651079
atomic_with_ghost!(
1066-
&this.inner.lock => fetch_or(BEING_UPGRADED);
1067-
ghost g => { }
1080+
&lock.lock => fetch_or(BEING_UPGRADED);
1081+
update prev -> next;
1082+
ghost g => {
1083+
assert(next == prev | BEING_UPGRADED);
1084+
assert(next & WRITER == prev & WRITER) by (bit_vector)
1085+
requires
1086+
next == prev | BEING_UPGRADED,
1087+
BEING_UPGRADED & WRITER == 0,
1088+
;
1089+
assert(next & UPGRADEABLE_READER == prev & UPGRADEABLE_READER) by (bit_vector)
1090+
requires
1091+
next == prev | BEING_UPGRADED,
1092+
BEING_UPGRADED & UPGRADEABLE_READER == 0,
1093+
;
1094+
assert(next & READER_MASK == prev & READER_MASK) by (bit_vector)
1095+
requires
1096+
next == prev | BEING_UPGRADED,
1097+
BEING_UPGRADED & READER_MASK == 0,
1098+
;
1099+
assert(next & MAX_READER_MASK == prev & MAX_READER_MASK) by (bit_vector)
1100+
requires
1101+
next == prev | BEING_UPGRADED,
1102+
BEING_UPGRADED & MAX_READER_MASK == 0,
1103+
;
1104+
assert(next & MAX_READER == prev & MAX_READER) by (bit_vector)
1105+
requires
1106+
next == prev | BEING_UPGRADED,
1107+
BEING_UPGRADED & MAX_READER == 0,
1108+
;
1109+
}
10681110
);
10691111
loop {
10701112
this = match this.try_upgrade() {
@@ -1076,31 +1118,131 @@ impl<T /*: ?Sized*/, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian>
10761118
/// Attempts to upgrade this upread guard to a write guard atomically.
10771119
///
10781120
/// This function will never spin-wait and will return immediately.
1079-
#[verifier::external_body]
1121+
#[verus_spec]
10801122
pub fn try_upgrade(self) -> Result<RwLockWriteGuard_<T, R, G>, Self> {
1123+
proof_decl! {
1124+
let tracked mut lock_perm: Option<RwFrac<T>> = None;
1125+
let tracked mut write_perm: Option<PointsTo<T>> = None;
1126+
let ghost mut lock_perm_id: Option<Loc> = None;
1127+
let ghost mut up_perm_id: Option<Loc> = None;
1128+
let ghost mut canon_perm_id: Option<Loc> = None;
1129+
}
1130+
let lock = self.inner.deref();
1131+
proof! {
1132+
use_type_invariant(&self);
1133+
use_type_invariant(lock);
1134+
lemma_consts_properties();
1135+
self.inner.deref_spec_eq();
1136+
assert(self.inner.deref_spec() == lock);
1137+
up_perm_id = Some(self.v_perm@.id());
1138+
canon_perm_id = Some(lock.cell_perm_id());
1139+
assert(up_perm_id->Some_0 == canon_perm_id->Some_0);
1140+
}
10811141
// let res = self.inner.lock.compare_exchange(
10821142
// UPGRADEABLE_READER | BEING_UPGRADED,
10831143
// WRITER | UPGRADEABLE_READER,
10841144
// AcqRel,
10851145
// Relaxed,
10861146
// );
10871147
let res = atomic_with_ghost!(
1088-
&self.inner.lock => compare_exchange(UPGRADEABLE_READER | BEING_UPGRADED, WRITER);
1148+
&lock.lock => compare_exchange(UPGRADEABLE_READER | BEING_UPGRADED, WRITER);
1149+
update prev -> next;
10891150
returning res;
1090-
ghost g => { }
1151+
ghost g => {
1152+
if res is Ok {
1153+
assert(prev == UPGRADEABLE_READER | BEING_UPGRADED);
1154+
assert(next == WRITER);
1155+
assert(prev & WRITER == 0usize) by (bit_vector)
1156+
requires
1157+
prev == UPGRADEABLE_READER | BEING_UPGRADED,
1158+
WRITER & UPGRADEABLE_READER == 0,
1159+
WRITER & BEING_UPGRADED == 0,
1160+
;
1161+
assert(prev & UPGRADEABLE_READER == UPGRADEABLE_READER) by (bit_vector)
1162+
requires
1163+
prev == UPGRADEABLE_READER | BEING_UPGRADED,
1164+
UPGRADEABLE_READER & BEING_UPGRADED == 0,
1165+
;
1166+
assert(prev & READER_MASK == 0usize) by (bit_vector)
1167+
requires
1168+
prev == UPGRADEABLE_READER | BEING_UPGRADED,
1169+
UPGRADEABLE_READER & READER_MASK == 0,
1170+
BEING_UPGRADED & READER_MASK == 0,
1171+
;
1172+
assert(prev & MAX_READER_MASK == 0usize) by (bit_vector)
1173+
requires
1174+
prev == UPGRADEABLE_READER | BEING_UPGRADED,
1175+
UPGRADEABLE_READER & MAX_READER_MASK == 0,
1176+
BEING_UPGRADED & MAX_READER_MASK == 0,
1177+
;
1178+
assert(prev & MAX_READER == 0usize) by (bit_vector)
1179+
requires
1180+
prev == UPGRADEABLE_READER | BEING_UPGRADED,
1181+
UPGRADEABLE_READER & MAX_READER == 0,
1182+
BEING_UPGRADED & MAX_READER == 0,
1183+
;
1184+
assert(g.cell_perm is Some);
1185+
assert(0 <= ((V_MAX_PERM_FRACS as int) - g.cell_perm->Some_0.frac()) - 1);
1186+
assert(((V_MAX_PERM_FRACS as int) - g.cell_perm->Some_0.frac()) - 1 <= 0);
1187+
assert(g.cell_perm->Some_0.frac() == (V_MAX_PERM_FRACS as int) - 1);
1188+
assert(g.cell_perm->Some_0.id() == lock.cell_perm_id());
1189+
lock_perm_id = Some(g.cell_perm->Some_0.id());
1190+
lock_perm = Some(g.cell_perm.tracked_take());
1191+
}
1192+
}
10911193
);
10921194
if res.is_ok() {
1093-
let this = core::mem::ManuallyDrop::new(self);
1094-
let inner = this.inner.clone();
1095-
let guard = unsafe { core::ptr::read(&this.guard) };
1096-
Ok(RwLockWriteGuard_ { inner, guard, v_perm: Tracked::assume_new() })
1195+
let mut this = core::mem::ManuallyDrop::new(self);
1196+
let inner = unsafe { Self::get_inner(&this) };
1197+
let guard = unsafe { Self::get_guard(&this) };
1198+
let Tracked(up_perm) = unsafe { Self::get_v_perm(&this) };
1199+
proof! {
1200+
let tracked mut rem = lock_perm.tracked_unwrap();
1201+
assert(rem.id() == lock_perm_id->Some_0);
1202+
assert(lock_perm_id->Some_0 == canon_perm_id->Some_0);
1203+
assert(up_perm == this@.v_perm@);
1204+
assert(this@.v_perm@.id() == up_perm_id->Some_0);
1205+
assert(up_perm.id() == this@.v_perm@.id());
1206+
let ghost up_cell_id = up_perm.resource().id();
1207+
assert(up_cell_id == inner.deref_spec().cell_id());
1208+
rem.combine(up_perm);
1209+
assert(rem.frac() == V_MAX_PERM_FRACS as int);
1210+
let tracked (full_perm, _) = rem.take_resource();
1211+
assert(full_perm.id() == up_cell_id);
1212+
write_perm = Some(full_perm);
1213+
}
1214+
Ok(RwLockWriteGuard_ { inner, guard, v_perm: Tracked(write_perm.tracked_unwrap()) })
10971215
} else {
10981216
Err(self)
10991217
}
11001218
}
1219+
1220+
#[verifier::external_body]
1221+
unsafe fn get_guard(me: &core::mem::ManuallyDrop<Self>) -> G::Guard {
1222+
core::ptr::read(&me.guard)
1223+
}
1224+
1225+
#[verifier::external_body]
1226+
#[verus_spec(
1227+
ret =>
1228+
ensures
1229+
ret.deref_spec() == me@.inner.deref_spec(),
1230+
)]
1231+
unsafe fn get_inner(me: &core::mem::ManuallyDrop<Self>) -> R {
1232+
core::ptr::read(&me.inner)
1233+
}
1234+
1235+
#[verifier::external_body]
1236+
#[verus_spec(
1237+
ret =>
1238+
ensures
1239+
ret@ == me@.v_perm@,
1240+
)]
1241+
unsafe fn get_v_perm(me: &core::mem::ManuallyDrop<Self>) -> Tracked<RwFrac<T>> {
1242+
core::ptr::read(&me.v_perm)
1243+
}
11011244
}
11021245

1103-
verus! {
11041246
impl<T /*: ?Sized*/, R: Deref<Target = RwLock<T, G>> + Clone, G: SpinGuardian> Deref
11051247
for RwLockUpgradeableGuard_<T, R, G>
11061248
{
@@ -1164,6 +1306,15 @@ proof fn lemma_consts_properties()
11641306
WRITER & MAX_READER_MASK == 0,
11651307
WRITER & MAX_READER == 0,
11661308
WRITER & UPGRADEABLE_READER == 0,
1309+
BEING_UPGRADED & WRITER == 0,
1310+
BEING_UPGRADED & UPGRADEABLE_READER == 0,
1311+
UPGRADEABLE_READER & BEING_UPGRADED == 0,
1312+
UPGRADEABLE_READER & READER_MASK == 0,
1313+
UPGRADEABLE_READER & MAX_READER_MASK == 0,
1314+
UPGRADEABLE_READER & MAX_READER == 0,
1315+
BEING_UPGRADED & READER_MASK == 0,
1316+
BEING_UPGRADED & MAX_READER_MASK == 0,
1317+
BEING_UPGRADED & MAX_READER == 0,
11671318
{
11681319
assert(0 & WRITER == 0) by (compute_only);
11691320
assert(0 & UPGRADEABLE_READER == 0) by (compute_only);
@@ -1184,6 +1335,15 @@ proof fn lemma_consts_properties()
11841335
assert(WRITER & MAX_READER_MASK == 0) by (compute_only);
11851336
assert(WRITER & MAX_READER == 0) by (compute_only);
11861337
assert(WRITER & UPGRADEABLE_READER == 0) by (compute_only);
1338+
assert(BEING_UPGRADED & WRITER == 0) by (compute_only);
1339+
assert(BEING_UPGRADED & UPGRADEABLE_READER == 0) by (compute_only);
1340+
assert(UPGRADEABLE_READER & BEING_UPGRADED == 0) by (compute_only);
1341+
assert(UPGRADEABLE_READER & READER_MASK == 0) by (compute_only);
1342+
assert(UPGRADEABLE_READER & MAX_READER_MASK == 0) by (compute_only);
1343+
assert(UPGRADEABLE_READER & MAX_READER == 0) by (compute_only);
1344+
assert(BEING_UPGRADED & READER_MASK == 0) by (compute_only);
1345+
assert(BEING_UPGRADED & MAX_READER_MASK == 0) by (compute_only);
1346+
assert(BEING_UPGRADED & MAX_READER == 0) by (compute_only);
11871347
}
11881348

11891349
proof fn lemma_consts_properties_value(prev: usize)

0 commit comments

Comments
 (0)