summaryrefslogtreecommitdiffstats
path: root/theories/lmpmc_queue_proof.v
diff options
context:
space:
mode:
Diffstat (limited to 'theories/lmpmc_queue_proof.v')
-rw-r--r--theories/lmpmc_queue_proof.v362
1 files changed, 362 insertions, 0 deletions
diff --git a/theories/lmpmc_queue_proof.v b/theories/lmpmc_queue_proof.v
new file mode 100644
index 0000000..fa732cc
--- /dev/null
+++ b/theories/lmpmc_queue_proof.v
@@ -0,0 +1,362 @@
1From iris.program_logic Require Import atomic.
2From iris.heap_lang Require Import notation proofmode.
3From iris.algebra.lib Require Import excl_auth.
4From iris.base_logic.lib Require Import invariants.
5From iris.base_logic.lib Require Import invariants mono_nat mono_list.
6From iris_named_props Require Import custom_syntax.
7
8From lmpmc Require fin_queue_spec lmpmc_queue_spec.
9From lmpmc Require Import upstream util.
10
11Section lmpmc_queue.
12 Context {fq : fin_queue_spec.fin_queue_hl}.
13
14 Definition new : val := λ: <>,
15 let: "ℓ_q" := fq.(fin_queue_spec.new) #() in ("ℓ_q", "ℓ_q").
16
17 Definition enqueue : val := (* passing arguments [ℓ_enq data] *)
18 fq.(fin_queue_spec.enqueue).
19
20 Definition try_dequeue : val := rec: "go" "ℓ_q" :=
21 match: fq.(fin_queue_spec.try_dequeue) "ℓ_q" with
22 InjL "v" =>
23 SOME "v"
24 | InjR "mℓ_nextq" =>
25 match: "mℓ_nextq" with
26 NONE => NONE
27 | SOME "ℓ_nextq" => "go" "ℓ_nextq"
28 end
29 end.
30
31 Definition link : val := (* passing arguments [ℓ_enq1 ℓ_deq2] *)
32 fq.(fin_queue_spec.finalize).
33
34 Section proofs.
35 Context `{!heapGS Σ} {fqp : fin_queue_spec.fin_queue_iris Σ fq}.
36
37 Record node := Node { ℓ_node : loc; vs_node : list val }.
38 Add Printing Constructor node.
39 Definition linked_single_queue_repr (n : node) (mℓ_nextq : option loc) : iProp Σ :=
40 fqp.(fin_queue_spec.queue_repr fq) n.(ℓ_node) n.(vs_node) (loc_to_val <$> mℓ_nextq).
41
42 Definition chain := list node.
43 Definition queue_repr ℓ_deq ℓ_enq (cvs : list val) : iProp Σ :=
44 ∃ (c : chain),
45 ⌜length c > 0⌝ ∗ ⌜ℓ_node <$> head c = Some ℓ_deq⌝ ∗
46 ⌜ℓ_node <$> last c = Some ℓ_enq⌝ ∗ ⌜cvs = c ≫= vs_node⌝ ∗
47 [∗ list] i ↦ l ∈ c, linked_single_queue_repr l (ℓ_node <$> c !! S i).
48
49 #[global] Instance queue_repr_timeless ℓ_deq ℓ_enq cvs : Timeless (queue_repr ℓ_deq ℓ_enq cvs) := _.
50
51 Lemma new_spec :
52 {{{ True }}}
53 new #()
54 {{{ (ℓ_deq ℓ_enq : loc), RET (#ℓ_deq, #ℓ_enq); queue_repr ℓ_deq ℓ_enq [] }}}.
55 Proof.
56 iIntros (Φ _) "HΦ". iUnfold new. wp_pures.
57 wp_apply (fqp.(fin_queue_spec.new_spec fq) with "[//]").
58 iIntros (ℓ) "H". wp_pures. iModIntro. iApply "HΦ".
59 unfold queue_repr. iExists [Node ℓ []].
60 iFrame. iSimplifyEq. by iSplit; first (iPureIntro; lia).
61 Qed.
62
63 Lemma enqueue_spec (ℓ_enq : loc) (data : val) :
64 ⊢ <<{ ∀∀ ℓ_deq cvs, queue_repr ℓ_deq ℓ_enq cvs }>>
65 enqueue #ℓ_enq data @ ∅
66 <<{ queue_repr ℓ_deq ℓ_enq (cvs ++ [data]) | RET #() }>>.
67 Proof.
68 iIntros "%Φ AU". iUnfold enqueue.
69
70 wp_bind (fin_queue_spec.enqueue _ _ _)%E.
71 awp_apply fqp.(fin_queue_spec.enqueue_spec fq).
72 rewrite /atomic_acc /=.
73 iMod "AU" as "(%ℓ_deq & %cvs & (%c & %Hclen & %Hhead & %Hlast & %Hcvs & Hqs) & Hclose)".
74 iModIntro.
75
76 destruct (last c) as [n_last|] eqn:Hlastn; last done.
77 iExists n_last.(vs_node).
78
79 apply last_Some in Hlastn as [c' ->].
80 iDestruct (big_sepL_insert_acc _ _ (length c') with "Hqs") as "[Hnode Hrepr]".
81 { by rewrite lookup_app_r // Nat.sub_diag. }
82 iSimplifyEq. iUnfold linked_single_queue_repr in "Hnode".
83
84 rewrite lookup_app_r; last lia.
85 replace (S (length c') - length c') with 1 by lia.
86 simplify_eq/=. iFrame.
87
88 iSplit.
89 - iDestruct "Hclose" as "[Hclose _]".
90 iIntros "Hnode".
91 iDestruct ("Hrepr" with "[Hnode //]") as "Hrepr".
92 rewrite list_insert_id; last first.
93 { by rewrite lookup_app_r // Nat.sub_diag. }
94 iMod ("Hclose" with "[$Hrepr]") as "AU".
95 { by rewrite last_snoc. }
96 done.
97 - iDestruct "Hclose" as "[_ Hclose]".
98 iIntros "Hnode".
99
100 set n_last' := Node n_last.(ℓ_node) (n_last.(vs_node) ++ [data]).
101 set c := c' ++ [n_last'].
102
103 iDestruct ("Hrepr" with "[Hnode]") as "Hrepr".
104 { rewrite /linked_single_queue_repr /=.
105 replace (ℓ_node n_last) with n_last'.(ℓ_node) by done.
106 by replace (vs_node n_last ++ [data]) with n_last'.(vs_node). }
107
108 iMod ("Hclose" with "[Hrepr]") as "HΦ".
109 { unfold queue_repr. iExists c. repeat iSplit; try done.
110 - iPureIntro. rewrite length_app /=. lia.
111 - iPureIntro. rewrite /c. by destruct c'; simplify_eq/=.
112 - iPureIntro. by rewrite /c last_snoc.
113 - iPureIntro. by rewrite /c !bind_app /= !app_nil_r app_assoc.
114 - rewrite insert_app_r_alt // Nat.sub_diag /=.
115 iApply (big_sepL_mono with "Hrepr").
116 { iIntros (i n Hi) "Hrepr".
117 rewrite -list_lookup_fmap fmap_app.
118 replace (ℓ_node <$> [n_last]) with (ℓ_node <$> [n_last']) by done.
119 by rewrite -fmap_app list_lookup_fmap. } }
120
121 iModIntro. iApply "HΦ".
122 Qed.
123
124 Lemma try_dequeue_spec (ℓ_deq : loc) :
125 ⊢ <<{ ∀∀ ℓ_enq cvs, queue_repr ℓ_deq ℓ_enq cvs }>>
126 try_dequeue #ℓ_deq @ ∅
127 <<{ queue_repr ℓ_deq ℓ_enq (tail cvs) | RET (val_opt_hl (head cvs)) }>>.
128 Proof.
129 revert ℓ_deq. iLöb as "IH". iIntros (ℓ_deq Φ) "AU". wp_rec.
130
131 awp_apply (fqp.(fin_queue_spec.try_dequeue_spec fq)).
132 rewrite /atomic_acc /=.
133 iMod "AU" as "(%ℓ_enq & %cvs & (%c & %Hclen & %Hhead & %Hlast & %Hcvs & Hqs) & Hclose)". iModIntro.
134
135 destruct c as [|n_head c']; first done.
136 iDestruct (big_sepL_cons with "Hqs") as "[Hnode Hqs]".
137 simpl. destruct (c' !! 0) as [n_next|] eqn:Hnextq.
138 - iExists n_head.(vs_node), (Some #n_next.(ℓ_node)). iSplitL "Hnode"; last iSplit.
139 + simplify_eq/=. by rewrite /linked_single_queue_repr /=.
140 + simplify_eq/=. iIntros "Hnode". iDestruct "Hclose" as "[Hclose _]".
141 pose c := n_head :: c'.
142 iAssert (linked_single_queue_repr n_head (ℓ_node <$> c !! S 0)) with "[Hnode]" as "Hnode".
143 { by rewrite /linked_single_queue_repr /= Hnextq. }
144 iAssert ([∗ list] i↦n ∈ c', linked_single_queue_repr n (ℓ_node <$> c !! S (S i)))%I with "[Hqs //]" as "Hqs".
145 iAssert ([∗ list] i↦n ∈ c, linked_single_queue_repr n (ℓ_node <$> c !! S i))%I with "[Hnode Hqs]" as "Hqs".
146 { iApply big_sepL_cons. iFrame. }
147 iAssert (queue_repr n_head.(ℓ_node) ℓ_enq (vs_node n_head ++ c' ≫= vs_node)) with "[$Hqs //]" as "Hrepr".
148 by iMod ("Hclose" with "Hrepr") as "Hrepr".
149 + simplify_eq/=. iIntros "Hnode".
150 destruct n_head.(vs_node) as [|x vs_head'] eqn:Hvs_head.
151 * simplify_eq/=. iDestruct "Hclose" as "[Hclose _]".
152
153 iDestruct (fqp.(fin_queue_spec.queue_fin_obtain fq) with "Hnode") as "#Hfin".
154
155 pose c := n_head :: c'.
156 iAssert (linked_single_queue_repr n_head (ℓ_node <$> c !! S 0)) with "[Hnode]" as "Hnode".
157 { by rewrite /linked_single_queue_repr /= Hnextq Hvs_head /=. }
158 iAssert ([∗ list] i↦n ∈ c', linked_single_queue_repr n (ℓ_node <$> c !! S (S i)))%I with "[Hqs //]" as "Hqs".
159 iAssert ([∗ list] i↦n ∈ c, linked_single_queue_repr n (ℓ_node <$> c !! S i))%I with "[Hnode Hqs]" as "Hqs".
160 { iApply big_sepL_cons. iFrame. }
161 iAssert (queue_repr n_head.(ℓ_node) ℓ_enq (vs_node n_head ++ c' ≫= vs_node)) with "[$Hqs //]" as "Hrepr".
162 rewrite Hvs_head /=. iMod ("Hclose" with "Hrepr") as "AU". iModIntro. wp_pures.
163 clear c c' Hclen Hlast Hnextq Hvs_head.
164
165 awp_apply "IH". rewrite /atomic_acc /=.
166 iMod "AU" as "(%ℓ_enq' & %cvs' & (%c'' & _ & %Hhead' & %Hlast' & %Hcvs' & Hqs') & Hclose)".
167 destruct c'' as [|n_head' c'']; first done.
168 iDestruct (big_sepL_cons with "Hqs'") as "[Hq0 Hqs']". simplify_eq/=.
169 iEval (rewrite /linked_single_queue_repr /=) in "Hq0".
170 rewrite -Hhead'.
171 iDestruct (fqp.(fin_queue_spec.queue_fin_agree fq) with "Hfin Hq0") as %[Hhead Hc''].
172 destruct (c'' !! 0) as [n_next'|] eqn:Hc''head; last done. simplify_eq/=.
173 rewrite -Hc''. clear Hhead' Hc'' n_next n_head.
174 assert (Hc''len : length c'' > 0). { by apply lookup_lt_Some in Hc''head. }
175
176 iAssert (queue_repr n_next'.(ℓ_node) ℓ_enq' (c'' ≫= vs_node)) with "[$Hqs']" as "Hrepr'".
177 { iPureIntro. repeat split; try done.
178 - by rewrite head_lookup Hc''head.
179 - enough (last c'' = last (n_head' :: c'')) as ->; first done.
180 destruct c''; first done. by rewrite last_cons_cons. }
181
182 iModIntro. iFrame. iSplit.
183 -- iIntros "(%d & %Hdlen & %Hdhead & %Hdlast & %Hdvs & Hrepr)".
184 rewrite Hhead /=. simplify_eq/=.
185 pose c := n_head' :: d.
186 iAssert (linked_single_queue_repr n_head' (ℓ_node <$> c !! S 0)) with "[Hq0]" as "Hq0".
187 { by rewrite /linked_single_queue_repr /= Hhead /= -head_lookup Hdhead /=. }
188 iAssert ([∗ list] i↦n ∈ c, linked_single_queue_repr n (ℓ_node <$> c !! S i))%I with "[Hq0 Hrepr]" as "Hrepr".
189 { iApply big_sepL_cons. iFrame. }
190 iAssert (queue_repr (ℓ_node n_head') ℓ_enq' (c'' ≫= vs_node)) with "[$Hrepr]" as "Hrepr".
191 { iPureIntro. repeat split; try done.
192 - unfold c. simpl. lia.
193 - unfold c. rewrite -Hdlast. by destruct d.
194 - unfold c. rewrite Hdvs. simplify_eq/=.
195 by rewrite Hhead. }
196 by iMod ("Hclose" with "Hrepr") as "AU".
197 -- iIntros "(%d & %Hdlen & %Hdhead & %Hdlast & %Hdvs & Hrepr)".
198 rewrite Hhead /=. simplify_eq/=.
199 pose c := n_head' :: d.
200 iAssert (linked_single_queue_repr n_head' (ℓ_node <$> c !! S 0)) with "[Hq0]" as "Hq0".
201 { by rewrite /linked_single_queue_repr /= Hhead /= -head_lookup Hdhead /=. }
202 iAssert ([∗ list] i↦n ∈ c, linked_single_queue_repr n (ℓ_node <$> c !! S i))%I with "[Hq0 Hrepr]" as "Hrepr".
203 { iApply big_sepL_cons. iFrame. }
204 iAssert (queue_repr (ℓ_node n_head') ℓ_enq' (tail (c'' ≫= vs_node))) with "[$Hrepr]" as "Hrepr".
205 { iPureIntro. repeat split; try done.
206 - unfold c. simpl. lia.
207 - unfold c. rewrite -Hdlast. by destruct d.
208 - unfold c. rewrite Hdvs. simplify_eq/=.
209 by rewrite Hhead. }
210 by iMod ("Hclose" with "Hrepr") as "AU".
211 * simplify_eq/=. iDestruct "Hclose" as "[_ Hclose]".
212
213 pose n_head' := Node (ℓ_node n_head) vs_head'.
214 pose c := n_head' :: c'.
215
216 iAssert (linked_single_queue_repr n_head' (ℓ_node <$> c !! S 0)) with "[Hnode]" as "Hnode".
217 { by rewrite /linked_single_queue_repr /= Hnextq /=. }
218 iAssert ([∗ list] i↦n ∈ c', linked_single_queue_repr n (ℓ_node <$> c !! S (S i)))%I with "[Hqs //]" as "Hqs".
219 iAssert ([∗ list] i↦n ∈ c, linked_single_queue_repr n (ℓ_node <$> c !! S i))%I with "[Hnode Hqs]" as "Hqs".
220 { iApply big_sepL_cons. iFrame. }
221 iAssert (queue_repr n_head.(ℓ_node) ℓ_enq (vs_node n_head' ++ c' ≫= vs_node)) with "[$Hqs]" as "Hrepr".
222 { iPureIntro. repeat split; try done. by destruct c'. }
223
224 iMod ("Hclose" with "Hrepr") as "Hrepr".
225 iModIntro. wp_pures. iApply "Hrepr".
226 - destruct c'; last done. simplify_eq/=. iClear "Hqs".
227 rewrite app_nil_r. clear Hclen.
228 iExists n_head.(vs_node), None. iSplitL "Hnode".
229 + by rewrite /linked_single_queue_repr /=.
230 + iSplit.
231 * iIntros "Hrepr". iDestruct "Hclose" as "[Hclose _]".
232 iMod ("Hclose" with "[Hrepr]") as "AU".
233 { iExists [n_head]. iFrame.
234 repeat iSplit; try done.
235 - iPureIntro. simpl. lia.
236 - simpl. by rewrite app_nil_r. }
237 done.
238 * iIntros "Hrepr". iDestruct "Hclose" as "[_ Hclose]".
239 set n_head' := Node n_head.(ℓ_node) (tail n_head.(vs_node)).
240 iMod ("Hclose" with "[Hrepr]") as "HΦ".
241 { iExists [n_head']. iFrame.
242 repeat iSplit; try done.
243 - iPureIntro. simpl. lia.
244 - simpl. by rewrite app_nil_r. }
245 destruct n_head.(vs_node) as [|v vs'];
246 iModIntro; wp_pures; iApply "HΦ".
247 Qed.
248
249 (** Linking two queues:
250 * _______________ _______________
251 * / Q1 \ / Q2 \
252 * ℓ_deq1 ... ℓ_enq1 <> ℓ_deq2 ... ℓ_enq2
253 * \ \ link op args / /
254 * \ \____________/ /
255 * \ Q1 <> Q2 /
256 * \______________________________/
257 *)
258 Lemma link_spec (ℓ_enq1 ℓ_deq2 : loc) :
259 ⊢ <<{ ∀∀ (b : bool) ℓ_deq1 ℓ_enq2 cvs1 cvs2, queue_repr ℓ_deq1 ℓ_enq1 cvs1 ∗
260 if b then queue_repr ℓ_deq2 ℓ_enq2 cvs2 else ⌜ℓ_deq1 = ℓ_deq2 ∧ ℓ_enq1 = ℓ_enq2⌝ }>>
261 link #ℓ_enq1 #ℓ_deq2 @ ∅
262 <<{ if b then queue_repr ℓ_deq1 ℓ_enq2 (cvs1 ++ cvs2) else True | RET #() }>>.
263 Proof.
264 iIntros "%Φ AU". iUnfold link.
265
266 wp_bind (fin_queue_spec.finalize _ _ _)%E.
267 awp_apply fqp.(fin_queue_spec.finalize_spec fq).
268 rewrite /atomic_acc /=.
269 iMod "AU" as (b ℓ_deq1 ℓ_enq2 cvs1 cvs2) "[[(%c1 & %Hclen1 & %Hhead1 & %Hlast1 & %Hcvs1 & Hqs1) Hqs2] Hclose]".
270 iModIntro.
271
272 destruct (last c1) as [n_last1|] eqn:Hlastn1; last done.
273 iExists n_last1.(vs_node).
274
275 apply last_Some in Hlastn1 as [c1' ->].
276 iDestruct (big_sepL_app with "Hqs1") as "[Hqs1 Hnode]".
277 iSimplifyEq. iDestruct "Hnode" as "[Hnode _]".
278 rewrite Nat.add_0_r.
279
280 rewrite lookup_ge_None_2 /=; last first.
281 { rewrite length_app /=. lia. }
282 iUnfold linked_single_queue_repr in "Hnode".
283 iSimplifyEq. iFrame.
284
285 iSplit.
286 - iDestruct "Hclose" as "[Hclose _]".
287 iIntros "Hnode".
288
289 iAssert (linked_single_queue_repr n_last1 (ℓ_node <$> (c1' ++ [n_last1]) !! S (length c1'))) with "[Hnode]" as "Hnode".
290 { rewrite /linked_single_queue_repr !lookup_app_r; last lia.
291 by assert (S (length c1') - length c1' = 1) as -> by lia. }
292
293 iDestruct (big_sepL_snoc with "[$Hqs1 $Hnode]") as "Hqs1'".
294
295 iPoseProof ("Hclose" with "[$Hqs1' $Hqs2]") as "Hqs".
296 { iPureIntro. repeat split; try done. by rewrite last_app. }
297 done.
298
299 - iDestruct "Hclose" as "[_ Hclose]".
300 iIntros "Hnode".
301
302 destruct b; last by iApply "Hclose".
303 iDestruct "Hqs2" as "(%c2 & %Hclen2 & %Hhead2 & %Hlast2 & %Hcvs2 & Hqs2)".
304
305 pose c := (c1' ++ [n_last1]) ++ c2.
306
307 iAssert (linked_single_queue_repr n_last1 (ℓ_node <$> c !! S (length c1'))) with "[Hnode]" as "Hnode".
308 { rewrite /linked_single_queue_repr /c !lookup_app_r; try (rewrite length_app /=; lia).
309 rewrite length_app /=. assert (S (length c1') - (length c1' + 1) = 0) as -> by lia.
310 rewrite -head_lookup Hhead2 //=. }
311
312 iDestruct (big_sepL_mono with "Hqs1") as "Hqs1".
313 { iIntros (i l Hi) "Hrepr".
314 iAssert (linked_single_queue_repr l (ℓ_node <$> c !! S i))%I with "[Hrepr]" as "Hrepr".
315 { rewrite /c lookup_app_l // length_app /=. apply lookup_lt_Some in Hi. lia. }
316 iExact "Hrepr". }
317
318 iDestruct (big_sepL_snoc with "[$Hqs1 $Hnode]") as "Hqs1'".
319
320 iDestruct (big_sepL_mono with "Hqs2") as "Hqs2".
321 { iIntros (i l Hi) "Hrepr".
322 iAssert (linked_single_queue_repr l (ℓ_node <$> c !! S (length (c1' ++ [n_last1]) + i)))%I with "[Hrepr]" as "Hrepr".
323 { rewrite /c length_app /= lookup_app_r length_app /=; last lia.
324 by assert (S i = S (length c1' + 1 + i) - (length c1' + 1)) as -> by lia. }
325 iExact "Hrepr". }
326 iSimplifyEq.
327
328 iDestruct (big_sepL_app with "[$Hqs1' $Hqs2]") as "Hqs". fold c.
329 rewrite -bind_app -/c.
330 iMod ("Hclose" with "[Hqs]") as "HΦ".
331 { iFrame. iPureIntro. repeat split; try done.
332 - rewrite /c !length_app /=. lia.
333 - rewrite /c head_app. case_match; last done. congruence.
334 - rewrite /c last_app. case_match; last done. congruence. }
335 iModIntro. iApply "HΦ".
336 Qed.
337
338 End proofs.
339
340End lmpmc_queue.
341
342Definition lmpmc_queue_hl (fq : fin_queue_spec.fin_queue_hl) : lmpmc_queue_spec.lmpmc_queue_hl.
343Proof.
344 by refine {| lmpmc_queue_spec.new := new;
345 lmpmc_queue_spec.enqueue := enqueue;
346 lmpmc_queue_spec.try_dequeue := try_dequeue;
347 lmpmc_queue_spec.link := link |}.
348Defined.
349
350Definition lmpmc_queue_iris `{!heapGS Σ}
351 (fq : fin_queue_spec.fin_queue_hl)
352 (fqp : fin_queue_spec.fin_queue_iris Σ fq) : lmpmc_queue_spec.lmpmc_queue_iris Σ (lmpmc_queue_hl fq).
353Proof.
354 by refine (lmpmc_queue_spec.LmpmcQueueIris _ _
355 (lmpmc_queue_hl fq) _ _
356 new_spec
357 enqueue_spec
358 try_dequeue_spec
359 link_spec).
360Defined.
361
362#[global] Typeclasses Opaque queue_repr.