-
Notifications
You must be signed in to change notification settings - Fork 82
/
Copy pathbasic_lock2.rs
76 lines (68 loc) · 2.04 KB
/
basic_lock2.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
use vstd::prelude::*;
use vstd::atomic_ghost::*;
use vstd::cell;
use vstd::cell::*;
use vstd::modes::*;
verus!{
struct_with_invariants!{
struct Lock<T> {
pub atomic: AtomicBool<_, Option<cell::PointsTo<T>>, _>,
pub cell: PCell<T>,
}
spec fn wf(self) -> bool {
invariant on atomic with (cell) is (v: bool, g: Option<cell::PointsTo<T>>) {
match g {
None => {
// When there's no PointsTo, the lock must be taken, thus
// the boolean value is 'true'.
v == true
}
Some(points_to) => {
points_to.id() == cell.id()
&& points_to.is_init()
&& v == false
}
}
}
}
}
impl<T> Lock<T> {
fn new(t: T) -> (lock: Self)
ensures lock.wf()
{
let (cell, Tracked(cell_perm)) = PCell::new(t);
let atomic = AtomicBool::new(Ghost(cell), false, Tracked(Some(cell_perm)));
Lock { atomic, cell }
}
fn acquire(&self) -> (points_to: Tracked<cell::PointsTo<T>>)
requires self.wf(),
ensures [email protected]() == self.cell.id(), [email protected]_init()
{
loop
invariant self.wf(),
{
let tracked mut points_to_opt = None;
let res = atomic_with_ghost!(&self.atomic => compare_exchange(false, true);
ghost points_to_inv => {
tracked_swap(&mut points_to_opt, &mut points_to_inv);
}
);
if res.is_ok() {
return Tracked(points_to_opt.tracked_unwrap());
}
}
}
fn release(&self, points_to: Tracked<cell::PointsTo<T>>)
requires
self.wf(),
[email protected]() == self.cell.id(), [email protected]_init()
{
atomic_with_ghost!(&self.atomic => store(false);
ghost points_to_inv => {
points_to_inv = Some(points_to.get());
}
);
}
}
}
fn main() { }