-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathflush_fence.v
More file actions
303 lines (267 loc) · 9.8 KB
/
Copy pathflush_fence.v
File metadata and controls
303 lines (267 loc) · 9.8 KB
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
From iris.proofmode Require Import tactics.
From self.base Require Import primitive_laws.
From self.lang Require Import lang.
From self.high Require Import dprop.
From self.lang Require Import notation lang.
From self.algebra Require Import view.
From self.base Require Import primitive_laws class_instances.
From self.base Require Import adequacy. (* To get [recv_adequace]. *)
From self.high Require Import proofmode wpc_proofmode.
From self.high Require Import dprop resources crash_weakestpre weakestpre
weakestpre_na recovery_weakestpre lifted_modalities modalities
post_crash_modality protocol no_buffer abstract_state_instances locations protocol adequacy.
From self.high.modalities Require Import fence.
Section program.
Definition incr_both (ℓx ℓy : loc) : expr :=
#ℓx <-_NA #37 ;;
Flush #ℓx ;;
Fence ;;
#ℓy <-_NA #1.
Definition recover (ℓx ℓy : loc) : expr :=
if: (!_NA #ℓy) = #1
then assert: (!_NA #ℓx = #37)
else #().
End program.
(* This is a simple example with a flush and a fence. *)
Section specification.
Context `{nvmG Σ}.
(* After a crash the following is possible: [a = 0, b = 0], [a = 37, b = 0],
and [a = 37, b = 1]. The case that is _not_ possible is: [a = 0, b = 1]. *)
(* Predicate used for the location [a]. *)
Definition ϕx : LocationProtocol bool :=
{| p_inv := λ (σ : bool) v, ⌜σ = false ∧ v = #0 ∨ (σ = true ∧ v = #37)⌝%I;
p_bumper n := n |}.
Global Instance ϕx_conditions : ProtocolConditions ϕx.
Proof. split; try apply _. iIntros. by iApply post_crash_flush_pure. Qed.
(* Predicate used for the location [b]. *)
Definition ϕy ℓx : LocationProtocol bool :=
{| p_inv := λ (σ : bool) v,
(⌜ σ = false ∧ v = #0 ⌝ ∨ ⌜ σ = true ∧ v = #1 ⌝ ∗ flush_lb ℓx ϕx true)%I;
p_bumper n := n |}.
Global Instance ϕy_conditions ℓx : ProtocolConditions (ϕy ℓx).
Proof.
split; [apply _| apply _| ].
iIntros (??) "I !>".
iDestruct "I" as "[(-> & ->)|(%eq & lb & _)]".
- iLeft. done.
- iRight. iDestruct (persist_lb_to_flush_lb with "lb") as "$". done.
Qed.
Definition crash_condition ℓx ℓy : dProp Σ :=
("pts" ∷ ∃ (na nb : bool),
"aPer" ∷ persist_lb ℓx ϕx na ∗
"bPer" ∷ persist_lb ℓy (ϕy ℓx) nb ∗
"aPts" ∷ ℓx ↦_{ϕx} [na] ∗
"yPts" ∷ ℓy ↦_{ϕy ℓx} [nb])%I.
Lemma prove_crash_condition ℓx ℓy na nb (ssA ssB : list bool) :
(* We need to know that both lists are strictly increasing list. *)
((∃ n, ssA = [n]) ∨ ssA = [false; true]) →
((∃ m, ssB = [m]) ∨ ssB = [false; true]) →
persist_lb ℓx ϕx na -∗
persist_lb ℓy (ϕy ℓx) nb -∗
ℓx ↦_{ϕx} ssA -∗
ℓy ↦_{ϕy ℓx} ssB -∗
<PC> crash_condition ℓx ℓy.
Proof.
iIntros (ssAEq ssBEq) "perA perB aPts yPts".
iModIntro.
iDestruct "perA" as "[perA (% & ? & #recA)]".
iDestruct "perB" as "[perB (% & ? & #recB)]".
iDestruct (crashed_in_if_rec with "recA aPts") as (?? prefA) "[recA' ptsA]".
iDestruct (crashed_in_agree with "recA recA'") as %<-.
iDestruct (crashed_in_if_rec with "recB yPts") as (?? prefB) "[recB' ptsB]".
iDestruct (crashed_in_agree with "recB recB'") as %<-.
iExistsN.
iDestruct (crashed_in_persist_lb with "recA'") as "$".
iDestruct (crashed_in_persist_lb with "recB'") as "$".
rewrite !list_fmap_id.
simpl.
iSplitL "ptsA".
- destruct ssAEq as [[? ->] | ->].
* apply prefix_app_singleton in prefA as [-> ->].
iFrame "ptsA".
* apply prefix_app_two in prefA as [[-> ->] | [-> ->]];
first iFrame "ptsA".
iDestruct (crashed_in_persist_lb with "recA") as "P".
iApply (mapsto_na_persist_lb with "ptsA P").
simpl.
rewrite /sqsubseteq.
lia.
- destruct ssBEq as [[? ->] | ->].
* apply prefix_app_singleton in prefB as [-> ->].
iFrame.
* apply prefix_app_two in prefB as [[-> ->] | [-> ->]];
first iFrame "ptsB".
iDestruct (crashed_in_persist_lb with "recB") as "P".
iApply (mapsto_na_persist_lb with "ptsB P").
simpl.
rewrite /sqsubseteq.
lia.
Qed.
Ltac solve_cc :=
try iModIntro (|={_}=> _)%I;
iApply (prove_crash_condition with "aPer bPer aPts yPts");
naive_solver.
Lemma wp_incr_both ℓx ℓy s E :
⊢ persist_lb ℓx ϕx false -∗
persist_lb ℓy (ϕy ℓx) false -∗
ℓx ↦_{ϕx} [false] -∗
ℓy ↦_{ϕy ℓx} [false] -∗
WPC (incr_both ℓx ℓy) @ s; E
{{ λ _, ℓx ↦_{ϕx} [false; true] ∗ ℓy ↦_{ϕy ℓx} [false; true] }}
{{ <PC> crash_condition ℓx ℓy }}.
Proof.
iIntros "#aPer #bPer aPts yPts".
rewrite /incr_both.
(* The first store *)
wpc_bind (_ <-_NA _)%E.
iApply wpc_atomic_no_mask.
iSplit; first solve_cc.
iApply (wp_store_na _ _ _ _ _ true with "[$aPts]").
{ reflexivity. }
{ done. }
{ naive_solver. }
simpl.
iNext. iIntros "aPts".
iSplit; first solve_cc.
iModIntro.
wpc_pures; first solve_cc.
(* The write back *)
wpc_bind (Flush _)%E.
iApply wpc_atomic_no_mask.
iSplit; first solve_cc.
iApply (wp_flush_na _ _ _ _ [false] with "[$aPts]").
iNext.
iIntros "(aPts & #pLowerBound & _)".
iSplit; first solve_cc.
iModIntro.
wpc_pures; first solve_cc.
(* The fence. *)
wpc_bind (Fence)%E.
iApply wpc_atomic_no_mask.
iSplit; first solve_cc.
iApply wp_fence. iModIntro. iModIntro.
iSplit; first solve_cc.
iModIntro.
wpc_pures; first solve_cc.
(* The last store *)
iApply wpc_atomic_no_mask.
iSplit; first solve_cc.
iApply (wp_store_na _ _ _ _ _ true with "[$yPts]").
{ reflexivity. }
{ done. }
{ iRight. iFrame "#". done. }
iNext. iIntros "yPts".
iSplit; first solve_cc.
iModIntro.
iFrame "aPts yPts".
Qed.
Lemma wpc_recover ℓx ℓy s E :
crash_condition ℓx ℓy -∗
WPC recover ℓx ℓy @ s; E
{{ _, True }}
{{ <PC> crash_condition ℓx ℓy }}.
Proof.
iNamed 1.
rewrite /recover.
(* iDestruct (mapsto_na_last with "aPts") as %[sA saEq]. *)
(* iDestruct (mapsto_na_last with "yPts") as %[sB sbEq]. *)
(* Load [ℓy]. *)
wpc_bind (!_NA _)%E.
iApply wpc_atomic_no_mask.
iSplit; first solve_cc.
iApply (wp_load_na _ _ _ _ ((ϕy ℓx).(p_inv) nb)%I
with "[$yPts]"); first done.
{ iIntros "!>" (?) "#I". iFrame "I". }
iIntros "!>" (?) "(yPts & I)".
iSplit; first solve_cc.
iModIntro.
wpc_pures; first solve_cc.
(* We now case on the disjunction in the invariant for [y]. *)
iDestruct "I" as "[(-> & ->)|([-> ->] & lb)]".
{ rewrite bool_decide_eq_false_2; last done.
wpc_pures; first solve_cc.
iModIntro. done. }
unfold assert.
wpc_pures; first solve_cc.
iDestruct (mapsto_na_flush_lb_incl [] with "lb aPts") as %incl.
replace na with true.
(* Load [ℓx]. *)
wpc_bind (!_NA _)%E.
iApply wpc_atomic_no_mask. iSplit; first solve_cc.
iApply (wp_load_na _ _ _ _ (λ v, ⌜v = #37⌝)%I with "[$aPts]"); first done.
{ iIntros "!>" (?) "[(% & %)|(% & %)]"; naive_solver. }
iIntros "!>" (?) "[aPts ->]".
iSplit; first solve_cc.
iModIntro.
wpc_pures; first solve_cc.
iModIntro.
done.
Qed.
Lemma incr_safe s E ℓx ℓy :
⊢ persist_lb ℓx ϕx false -∗
persist_lb ℓy (ϕy ℓx) false -∗
ℓx ↦_{ϕx} [false] -∗
ℓy ↦_{ϕy ℓx} [false] -∗
wpr s E (incr_both ℓx ℓy) (recover ℓx ℓy)
(λ _, ℓx ↦_{ϕx} [false; true] ∗ ℓy ↦_{ϕy ℓx} [false; true]) (λ _, True%I).
Proof.
iIntros "a b c d".
iApply (idempotence_wpr _ _ _ _ _ _ (<PC> crash_condition ℓx ℓy)%I
with "[a b c d] []").
{ iApply (wp_incr_both _ _ s E with "a b c d"). }
iModIntro. iModIntro.
iIntros "R".
iModIntro.
iApply (wpc_recover with "R").
Qed.
End specification.
(* We now create a closed proof. *)
Definition init_heap ℓx ℓy : gmap loc val := {[ ℓx := #0; ℓy := #0 ]}.
Lemma incr_safe_proof ℓx ℓy :
ℓx ≠ ℓy →
recv_adequate NotStuck
(incr_both ℓx ℓy `at` ⊥)
(recover ℓx ℓy `at` ⊥)
(initial_heap (init_heap ℓx ℓy),
const (MaxNat 0) <$> (init_heap ℓx ℓy))
(λ v _, True) (λ v _, True).
Proof.
intros neq.
eapply (high_recv_adequacy_2 nvmΣ _ _ _ (λ _, True) (λ _, True) 0
(init_heap ℓx ℓy)
({[ ℓx; ℓy ]})
∅).
{ set_solver. }
{ set_solver. }
iIntros (nD).
set (ℓx_lif := {| loc_state := bool; loc_init := false; loc_prot := ϕx |}).
set (ℓy_lif := {| loc_state := bool; loc_init := false; loc_prot := ϕy ℓx |}).
set (lif := {[ℓx := ℓx_lif; ℓy := ℓy_lif ]} : gmap loc loc_info).
exists lif.
rewrite /lif.
split; first set_solver.
iIntros "M _ _".
setoid_rewrite (restrict_id {[ℓx; ℓy]}); last set_solver.
rewrite /init_heap.
rewrite big_sepM_insert. 2: { apply lookup_singleton_ne. done. }
iDestruct "M" as "[(% & %look & #pa & ptsA) M]".
rewrite big_sepM_singleton.
iDestruct "M" as "(% & %look' & #pb & ptsB)".
simplify_eq.
(* Simplify things. *)
rewrite lookup_insert in look.
rewrite lookup_insert_ne in look'; last done.
rewrite lookup_insert in look'.
simplify_eq /=.
rewrite big_sepM2_insert; try (apply lookup_singleton_ne; done).
rewrite big_sepM2_singleton.
iSplit.
{ simpl. iSplitPure; naive_solver. }
iApply (wpr_mono with "[ptsA ptsB]").
{ iApply (incr_safe with "pa pb ptsA ptsB"). }
iSplit.
- iIntros. done.
- iModIntro. done.
Qed.
(* Uncomment the next line to see that the proof is truly closed. *)
(* Print Assumptions incr_safe_proof. *)