summaryrefslogtreecommitdiffstats
path: root/theories/basic_queue_proof.v
diff options
context:
space:
mode:
Diffstat (limited to 'theories/basic_queue_proof.v')
-rw-r--r--theories/basic_queue_proof.v652
1 files changed, 652 insertions, 0 deletions
diff --git a/theories/basic_queue_proof.v b/theories/basic_queue_proof.v
new file mode 100644
index 0000000..f169878
--- /dev/null
+++ b/theories/basic_queue_proof.v
@@ -0,0 +1,652 @@
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 Import basic_queue_spec upstream util.
9
10Definition new_node : val := λ: "data",
11 let: "ℓ_node" := AllocN #2 #() in
12 "ℓ_node" <- "data";;
13 "ℓ_node" +ₗ #1 <- NONE;;
14 "ℓ_node".
15
16Definition new : val := λ: <>,
17 let: "ℓ_node" := new_node #() in
18 AllocN #2 "ℓ_node".
19
20Definition set_tail : val := rec: "go" "ℓ_q" "ℓ_node" :=
21 let: "ℓ_tail" := !("ℓ_q" +ₗ #1) in
22 match: !("ℓ_tail" +ₗ #1) with
23 NONE =>
24 if: CAS ("ℓ_tail" +ₗ #1) NONE (SOME "ℓ_node") then
25 #()
26 else
27 "go" "ℓ_q" "ℓ_node"
28 | SOME "ℓ_next" =>
29 CAS ("ℓ_q" +ₗ #1) "ℓ_tail" "ℓ_next";;
30 "go" "ℓ_q" "ℓ_node"
31 end.
32
33Definition enqueue : val := λ: "ℓ_q" "data",
34 set_tail "ℓ_q" (new_node "data").
35
36Definition try_dequeue : val := rec: "go" "ℓ_q" :=
37 let: "ℓ_head" := !"ℓ_q" in
38 match: !("ℓ_head" +ₗ #1) with
39 NONE => NONE
40 | SOME "ℓ_next" =>
41 let: "v" := !"ℓ_next" in
42 if: CAS "ℓ_q" "ℓ_head" "ℓ_next" then
43 SOME "v"
44 else
45 "go" "ℓ_q"
46 end.
47
48Class basic_queueG Σ := BasicQueueG
49 { basic_queue_mono_natG :: mono_natG Σ;
50 basic_queue_mono_listG :: mono_listG (prodO locO valO) Σ; }.
51
52Definition basic_queueΣ : gFunctors :=
53 #[ mono_natΣ; mono_listΣ (prodO locO valO) ].
54
55#[global] Instance subG_basic_queueΣ {Σ} : subG basic_queueΣ Σ → basic_queueG Σ.
56Proof. solve_inG. Qed.
57
58Section basic_queue.
59 Context `{!heapGS Σ, !basic_queueG Σ}.
60
61 Record gstate :=
62 { γ_hist : gname;
63 γ_hpos : gname; }.
64 Definition gstate_to_pair (γ : gstate) :=
65 (γ.(γ_hist), γ.(γ_hpos)).
66 Definition gstate_of_pair '(γ_hist, γ_hpos) :=
67 {| γ_hist := γ_hist; γ_hpos := γ_hpos |}.
68 Instance gstate_eq_dec : EqDecision gstate := ltac:(solve_decision).
69 Instance gstate_countable : Countable gstate.
70 Proof.
71 refine {| encode := encode ∘ gstate_to_pair;
72 decode := fmap gstate_of_pair ∘ decode; |}.
73 intros []. by rewrite /= decode_encode.
74 Qed.
75
76 Definition node_repr (ℓ : loc) (data : val) (mℓ_next : option loc) : iProp Σ :=
77 ("Hndata" ∷ ℓ ↦□ data) ∗
78 ("Hnnext" ∷ (ℓ +ₗ 1) ↦ loc_opt_hl mℓ_next).
79
80 Definition loc_at (hist : list (loc * val)) i :=
81 hist.*1 !! i.
82 Definition val_at (hist : list (loc * val)) i :=
83 hist.*2 !! i.
84
85 Lemma loc_at_prefix xs xs' i ℓ :
86 loc_at xs i = Some ℓ → xs `prefix_of` xs' → loc_at xs' i = Some ℓ.
87 Proof.
88 unfold loc_at. intros Hxs Hpre.
89 eapply prefix_lookup_Some; first exact Hxs.
90 by apply prefix_of_fmap.
91 Qed.
92
93 Lemma val_at_prefix xs xs' i ℓ :
94 val_at xs i = Some ℓ → xs `prefix_of` xs' → val_at xs' i = Some ℓ.
95 Proof.
96 unfold val_at. intros Hxs Hpre.
97 eapply prefix_lookup_Some; first exact Hxs.
98 by apply prefix_of_fmap.
99 Qed.
100
101 Lemma loc_at_val_at_Some xs i ℓ :
102 loc_at xs i = Some ℓ → ∃ v, val_at xs i = Some v.
103 Proof.
104 unfold loc_at, val_at. rewrite [xs.*2 !! i]list_lookup_fmap.
105 intros [[ℓ' v] [-> ->]]%list_lookup_fmap_Some_1. by exists v.
106 Qed.
107
108 Lemma loc_at_val_at_combine {hist i ℓ v} :
109 loc_at hist i = Some ℓ →
110 val_at hist i = Some v →
111 hist !! i = Some (ℓ, v).
112 Proof.
113 unfold loc_at, val_at. intros Hloc Hval.
114 rewrite list_lookup_fmap in Hloc.
115 rewrite list_lookup_fmap in Hval.
116 destruct (hist !! i) as [[ℓ' v']|]; last done.
117 simpl in *. congruence.
118 Qed.
119
120 Lemma loc_at_Some_length hist i ℓ :
121 loc_at hist i = Some ℓ → i < length hist.
122 Proof.
123 intros Hloc%lookup_lt_Some.
124 by rewrite length_fmap in Hloc.
125 Qed.
126
127 Lemma loc_at_drop hist n i ℓ :
128 loc_at hist (n + i) = Some ℓ →
129 loc_at (drop n hist) i = Some ℓ.
130 Proof.
131 unfold loc_at. intros Hloc.
132 by rewrite list_lookup_fmap lookup_drop -list_lookup_fmap.
133 Qed.
134
135 Lemma loc_at_drop_2 hist n i :
136 loc_at (drop n hist) i = loc_at hist (n + i).
137 Proof. by rewrite /loc_at list_lookup_fmap lookup_drop -list_lookup_fmap. Qed.
138
139 Lemma val_at_drop hist n i ℓ :
140 val_at hist (n + i) = Some ℓ →
141 val_at (drop n hist) i = Some ℓ.
142 Proof.
143 unfold val_at. intros Hval.
144 by rewrite list_lookup_fmap lookup_drop -list_lookup_fmap.
145 Qed.
146
147 Definition hist_repr (hist : list (loc * val)) : iProp Σ :=
148 [∗ list] i ↦ '(ℓ, data) ∈ hist, node_repr ℓ data (loc_at hist (S i)).
149
150 Lemma hist_repr_peek_1 hist i ℓ data :
151 loc_at hist i = Some ℓ →
152 val_at hist i = Some data →
153 hist_repr hist -∗
154 node_repr ℓ data (loc_at hist (S i)) ∗
155 (node_repr ℓ data (loc_at hist (S i)) -∗ hist_repr hist).
156 Proof.
157 iIntros "%Hloc %Hval Hrepr".
158 pose proof (loc_at_val_at_combine Hloc Hval) as Hi.
159 iPoseProof (big_sepL_lookup_acc with "Hrepr") as "[Hnode Hclose]".
160 { apply Hi. }
161 iFrame.
162 Qed.
163
164 Lemma hist_repr_peek_2 hist i ℓ :
165 loc_at hist i = Some ℓ →
166 hist_repr hist -∗
167 ∃ data, node_repr ℓ data (loc_at hist (S i)) ∗
168 (node_repr ℓ data (loc_at hist (S i)) -∗ hist_repr hist).
169 Proof.
170 iIntros "%Hloc Hrepr".
171 assert (∃ v, val_at hist i = Some v) as [v Hval].
172 { by apply loc_at_val_at_Some in Hloc. }
173 iExists v. by iApply hist_repr_peek_1.
174 Qed.
175
176 Lemma hist_repr_peek_3 hist i ℓ :
177 loc_at hist i = Some ℓ →
178 hist_repr hist -∗
179 (ℓ +ₗ 1) ↦ loc_opt_hl (loc_at hist (S i)) ∗
180 ((ℓ +ₗ 1) ↦ loc_opt_hl (loc_at hist (S i)) -∗ hist_repr hist).
181 Proof.
182 iIntros "%Hloc Hrepr".
183 iDestruct (hist_repr_peek_2 with "[$]") as "(%v & @ & Hclose)"; first done.
184 iFrame. iIntros "Hnnext". iApply "Hclose". iFrame.
185 Qed.
186
187 Lemma loc_at_None hist pos :
188 loc_at hist pos = None → hist !! pos = None.
189 Proof.
190 rewrite /loc_at list_lookup_fmap.
191 by destruct (hist !! pos).
192 Qed.
193
194 Lemma loc_at_length hist pos :
195 loc_at hist pos = None → length hist ≤ pos.
196 Proof.
197 intros H%loc_at_None.
198 by apply lookup_ge_None.
199 Qed.
200
201 Lemma hist_repr_proj hist i ℓ :
202 loc_at hist i = Some ℓ →
203 hist_repr hist -∗
204 (∃ v, (ℓ +ₗ 1) ↦ v) ∗ hist_repr (drop (S i) hist).
205 Proof.
206 iIntros "%Hℓi Hrepr".
207 iDestruct (big_sepL_take_drop _ _ (S i) with "Hrepr") as "[Hrepr1 Hrepr2]".
208
209 rewrite /loc_at list_lookup_fmap in Hℓi.
210 destruct (hist !! i) as [[ℓ' v]|] eqn:Hi; last done.
211 simpl in *. injection Hℓi as ->.
212
213 iDestruct (big_sepL_lookup_acc with "Hrepr1") as "[Hrepr Hclose]".
214 { rewrite lookup_take_lt //. lia. }
215 iSimplifyEq. iDestruct "Hrepr" as "@". iFrame.
216 iClear "Hndata Hclose".
217
218 iAssert (hist_repr (drop (S i) hist)) with "[Hrepr2]" as "Hrepr2".
219 { unfold hist_repr. iApply (big_sepL_mono with "Hrepr2").
220 iIntros (k [ℓ' v'] Hk) "Hrepr".
221 by rewrite loc_at_drop_2 Nat.add_succ_l Nat.add_succ_r. }
222 done.
223 Qed.
224
225 Lemma loc_at_inj_aux hist i j ℓ :
226 i < j →
227 loc_at hist i = Some ℓ →
228 loc_at hist j = Some ℓ →
229 hist_repr hist -∗
230 False.
231 Proof.
232 iIntros "%ij %Hloci %Hlocj Hrepr".
233 assert (i < length hist). { by eapply loc_at_Some_length. }
234 assert (j < length hist). { by eapply loc_at_Some_length. }
235 assert (∃ n, j = S i + n) as [n ->].
236 { exists (j - i - 1). lia. }
237 iPoseProof (hist_repr_proj hist i ℓ Hloci with "Hrepr") as "[[%ni Hℓi] Hrepr']".
238
239 assert (Hlocj' : loc_at (drop (S i) hist) n = Some ℓ).
240 { by apply loc_at_drop. }
241
242 iPoseProof (hist_repr_proj _ n ℓ Hlocj' with "Hrepr'") as "[[%nj Hℓj] _]".
243 by iCombine "Hℓi Hℓj" gives %[? _].
244 Qed.
245
246 Lemma loc_at_inj {hist i j ℓ} :
247 loc_at hist i = Some ℓ →
248 loc_at hist j = Some ℓ →
249 hist_repr hist -∗
250 ⌜i = j⌝.
251 Proof.
252 iIntros "%Hloci %Hlocj Hrepr".
253 destruct (loc_at_val_at_Some hist i ℓ Hloci) as [vi Hvali].
254 destruct (loc_at_val_at_Some hist j ℓ Hlocj) as [vj Hvalj].
255 destruct (decide (i < j)) as [Hij|Hij].
256 - (* i < j *)
257 by iPoseProof (loc_at_inj_aux with "Hrepr") as "H".
258 - (* i ≥ j *)
259 destruct (decide (j < i)) as [Hji|Hji].
260 + (* j < i *)
261 by iPoseProof (loc_at_inj_aux with "Hrepr") as "H".
262 + (* i = j *)
263 iPureIntro. lia.
264 Qed.
265
266 Definition queue_repr_1 (γs : gstate) ℓ_q (vs : list val) : iProp Σ :=
267 ∃ (hist : list (loc * val)) (ℓ_head ℓ_tail : loc) (hpos tpos : nat),
268 ("Hhead" ∷ ℓ_q ↦ #ℓ_head) ∗
269 ("Htail" ∷ (ℓ_q +ₗ 1) ↦ #ℓ_tail) ∗
270 ("Hrepr" ∷ hist_repr hist) ∗
271 ("Hhist●" ∷ γs.(γ_hist) ↪●ML hist) ∗
272 ("Hhpos●" ∷ γs.(γ_hpos) ↪●MN hpos) ∗
273 ("%Hℓhpos" ∷ ⌜loc_at hist hpos = Some ℓ_head⌝) ∗
274 ("%Hℓtpos" ∷ ⌜loc_at hist tpos = Some ℓ_tail⌝) ∗
275 ("%Hvs" ∷ ⌜vs = (drop (S hpos) hist).*2⌝).
276
277 Definition queue_repr ℓ_q (vs : list val) : iProp Σ :=
278 ∃ (γs : gstate), meta ℓ_q nroot γs ∗ queue_repr_1 γs ℓ_q vs.
279
280 #[global] Instance queue_repr_timeless ℓ_q vs : Timeless (queue_repr ℓ_q vs) := _.
281
282 Lemma new_node_spec data :
283 {{{ True }}}
284 new_node data
285 {{{ (ℓ : loc), RET #ℓ; node_repr ℓ data None }}}.
286 Proof.
287 iIntros "%Φ _ HΦ". iUnfold new_node. wp_lam.
288 wp_alloc ℓ_node as "Hℓ_node"; first done.
289 iDestruct (array_cons with "Hℓ_node") as "[Hℓ_node0 Hℓ_node1]".
290 iDestruct (array_cons with "Hℓ_node1") as "[Hℓ_node1 _]".
291 wp_let. do 2 wp_store.
292 iMod (pointsto_persist with "Hℓ_node0") as "Hℓ_node0".
293 iModIntro. iApply "HΦ". by iFrame.
294 Qed.
295
296 Lemma new_spec :
297 {{{ True }}}
298 new #()
299 {{{ (ℓ : loc), RET #ℓ; queue_repr ℓ [] }}}.
300 Proof.
301 iIntros "%Φ _ HΦ". iUnfold new.
302 wp_lam. wp_apply (new_node_spec with "[//]").
303 iIntros (ℓ_node) "Hnode". wp_let.
304
305 set ℓ_head := ℓ_node. set ℓ_tail := ℓ_node.
306 set hpos := 0. set tpos := 0.
307 set hist := [(ℓ_node, #())] : list (loc * val).
308 iAssert (hist_repr hist) with "[$Hnode //]" as "Hrepr".
309
310 iMod (mono_list_own_alloc hist) as "[%γ_hist [Hhist● _]]".
311 iMod (mono_nat_own_alloc hpos) as "[%γ_hpos [Hhpos● _]]".
312 set γs := {| γ_hist := γ_hist; γ_hpos := γ_hpos |}.
313
314 iApply wp_fupd. iApply wp_allocN; [lia|done|].
315 iIntros "!> %ℓ [Hℓ [Htok _]]".
316 iDestruct (array_cons with "Hℓ") as "[Hℓ0 Hℓ1]".
317 iDestruct (array_cons with "Hℓ1") as "[Hℓ1 _]".
318 rewrite Loc.add_0.
319
320 iMod (meta_set ⊤ ℓ γs nroot with "Htok") as "Hmeta"; first done.
321
322 iApply "HΦ". iModIntro. iFrame. by iExists tpos.
323 Qed.
324
325 Lemma try_bump_tail_spec hist0 tpos ℓ_old ℓ_new ℓ_q γs :
326 loc_at hist0 tpos = Some ℓ_old →
327 loc_at hist0 (S tpos) = Some ℓ_new →
328 γs.(γ_hist) ↪◯ML hist0 -∗
329 <<{ ∀∀ vs, queue_repr_1 γs ℓ_q vs }>>
330 CAS #(ℓ_q +ₗ 1) #ℓ_old #ℓ_new @ ∅
331 <<{ ∃∃ (b : bool), queue_repr_1 γs ℓ_q vs | RET #b }>>.
332 Proof.
333 iIntros "%Hold %Hnew #Hhist◯ %Φ AU".
334 wp_bind (CmpXchg _ _ _)%E.
335 iMod "AU" as "(%vs & (%hist1 & %ℓ_head & %ℓ_tail & %hpos & %tpos' & @) & [_ Hclose])".
336 iAssert ⌜hist0 `prefix_of` hist1⌝%I as %Hhist01.
337 { by iDestruct (mono_list_auth_lb_own_valid with "Hhist● Hhist◯") as "[_ ?]". }
338
339 destruct (decide (ℓ_tail = ℓ_old)) as [->|].
340 - (* The tail has not been updated yet *)
341 wp_cmpxchg_suc.
342
343 iAssert (queue_repr_1 γs ℓ_q vs) with "[$Hhead $Htail $Hhist● $Hhpos● $Hrepr]" as "Hq".
344 { iPureIntro.
345 repeat split; try done || lia.
346 exists (S tpos). repeat split; try done.
347 by eapply loc_at_prefix. }
348 iMod ("Hclose" with "[$Hq]") as "HΦ".
349 iModIntro. wp_pures. iApply "HΦ".
350 - (* The tail has been updated in the meantime *)
351 wp_cmpxchg_fail.
352 iAssert (queue_repr_1 γs ℓ_q vs) with "[$Hhead $Htail $Hhist● $Hhpos● $Hrepr]" as "Hq".
353 { iExists tpos'. by iFrameNamed. }
354 iMod ("Hclose" with "[$Hq]") as "HΦ".
355 iModIntro. wp_pures. iApply "HΦ".
356 Qed.
357
358 (* Given a history that is represented, after updating the [next]
359 pointer of the current tail node to a new tail node, we obtain a
360 new (extended) history (with the new tail node appended). *)
361 Lemma hist_repr_snoc hist tpos (ℓ_tail ℓ_new : loc) data :
362 length hist = S tpos →
363 loc_at hist tpos = Some ℓ_tail →
364 node_repr ℓ_new data None -∗
365 hist_repr hist -∗
366 (ℓ_tail +ₗ 1) ↦ loc_opt_hl None ∗
367 ((ℓ_tail +ₗ 1) ↦ loc_opt_hl (Some ℓ_new) -∗ hist_repr (hist ++ [(ℓ_new, data)])).
368 Proof.
369 unfold loc_at.
370 iIntros "%Hhistlen %Hloc @ Hhist".
371 rewrite list_lookup_fmap in Hloc.
372 destruct (hist !! tpos) as [[ℓ_tail' v_tail]|] eqn:Htpos; last done.
373 injection Hloc as ->.
374 apply list_elem_of_split_length in Htpos as (hist' & empty & -> & Htpos).
375 rewrite length_app length_cons -Htpos in Hhistlen.
376 assert (empty = []) as ->. { apply nil_length_inv. lia. }
377 clear Hhistlen Htpos.
378
379 iPoseProof (big_sepL_snoc with "Hhist") as "[Hinit Htail]".
380 iNamedSuffix "Htail" "_tail".
381
382 iSimplifyEq.
383 assert (loc_at (hist' ++ [(ℓ_tail, v_tail)]) (S (length hist')) = None) as ->.
384 { apply lookup_ge_None_2. rewrite length_fmap length_app length_cons /=. lia. }
385 iFrame "Hnnext_tail". iIntros "Hnnext_tail".
386 iSimplifyEq. rewrite /hist_repr.
387 iApply big_sepL_snoc.
388 iSplitR "Hndata Hnnext".
389 - iApply big_sepL_snoc. iSplitL "Hinit".
390 + iApply (big_sepL_mono with "Hinit").
391 iIntros (k [ℓ v] Hk) "Hrepr".
392 assert (loc_at ((hist' ++ [(ℓ_tail, v_tail)]) ++ [(ℓ_new, data)]) (S k) = loc_at (hist' ++ [(ℓ_tail, v_tail)]) (S k)) as ->.
393 { rewrite /loc_at !list_lookup_fmap lookup_app_l // length_app /=.
394 apply lookup_lt_Some in Hk. lia. }
395 done.
396 + iFrame.
397 rewrite /loc_at list_lookup_fmap lookup_app_r; last first.
398 { rewrite length_app /=. lia. }
399 by rewrite length_app /= Nat.add_1_r Nat.sub_diag.
400 - iFrame.
401 rewrite /= /loc_at length_app /= Nat.add_1_r list_lookup_fmap lookup_app_r.
402 * by rewrite !length_app /= !Nat.add_1_r Nat.sub_succ -Arith_base.minus_Sn_m_stt // Nat.sub_diag.
403 * rewrite length_app /= Nat.add_1_r. lia.
404 Qed.
405
406 Lemma set_tail_spec (ℓ_q ℓ_node : loc) data :
407 node_repr ℓ_node data None -∗
408 <<{ ∀∀ vs, queue_repr ℓ_q vs }>>
409 set_tail #ℓ_q #ℓ_node @ ∅
410 <<{ queue_repr ℓ_q (vs ++ [data]) | RET #() }>>.
411 Proof.
412 iIntros "@ %Φ AU". iLöb as "IH". wp_rec.
413
414 wp_pures. wp_bind (! _)%E.
415 iMod "AU" as "(%vs & (%γs & #Hγs & %hist0 & %ℓ_head & %ℓ_tail & %hpos & %tpos & @) & [Hclose _])".
416 iDestruct (mono_list_lb_own_get with "Hhist●") as "#Hhist0◯".
417 wp_load. iSimpl in "Hrepr".
418 rename Hℓtpos into Hℓtpos0.
419 iAssert (queue_repr_1 γs ℓ_q vs) with "[$Hhead $Htail $Hhist● $Hhpos● $Hrepr]" as "Hq".
420 { iExists tpos. by iFrameNamed. }
421 iMod ("Hclose" with "[$]") as "AU". clear Hvs Hℓhpos hpos vs ℓ_head.
422 iModIntro. wp_let. wp_pure.
423
424 wp_bind (! _)%E.
425 iMod "AU" as "(%vs & (%γs' & Hγs' & %hist2 & %ℓ_head & %ℓ_tail'' & %hpos & %tpos'' & @) & [Hclose _])".
426 iDestruct (meta_agree with "Hγs Hγs'") as "<- {Hγs'}".
427 iDestruct (mono_list_auth_lb_own_valid with "Hhist● Hhist0◯") as %Hhist02.
428 iDestruct (mono_list_lb_own_get with "Hhist●") as "#Hhist2◯".
429 destruct Hhist02 as [_ Hhist02]. rename Hℓtpos into Hℓtpos2.
430 assert (Hℓtpos0'' : loc_at hist2 tpos = Some ℓ_tail).
431 { by eapply loc_at_prefix. } clear Hℓtpos0.
432 wp_pures.
433 iDestruct (hist_repr_peek_2 with "[$Hrepr]") as "(%w & Hnrepr & Hrepr)"; first done.
434 iNamedSuffix "Hnrepr" "_tail".
435 wp_load.
436 iPoseProof ("Hrepr" with "[$]") as "Hrepr".
437 iAssert (queue_repr_1 γs ℓ_q vs) with "[$Hhead $Htail $Hhist● $Hhpos● $Hrepr]" as "Hq".
438 { iExists tpos''. by iFrameNamed. }
439 iMod ("Hclose" with "[$]") as "AU". clear Hvs Hℓhpos Hℓtpos2 hpos vs ℓ_head ℓ_tail''.
440 iModIntro.
441
442 destruct (loc_at hist2 (S tpos)) as [ℓ_next|] eqn:Htpos2.
443 + (* it is not the last node *)
444 simpl. wp_pures. wp_bind (Snd (CmpXchg _ _ _))%E.
445 awp_apply (try_bump_tail_spec with "[//]").
446 { apply Hℓtpos0''. }
447 { done. }
448 rewrite /atomic_acc /=.
449 iMod "AU" as "(%vs & (%γs' & Hγs' & Hrepr) & [Hclose _])".
450 iDestruct (meta_agree with "Hγs Hγs'") as "<- {Hγs'}".
451 iModIntro. iExists vs. iFrame "Hrepr". iSplit.
452 * iFrame. iIntros "Hrepr". by iApply ("Hclose" with "[$Hrepr]").
453 * iIntros "%b Hrepr".
454 iMod ("Hclose" with "[$Hrepr //]") as "AU".
455 iModIntro. wp_pures.
456 by iApply ("IH" with "[$] [$] [$]").
457 + (* it is the last (non-final) node *)
458 simpl. wp_pures. wp_bind (CmpXchg _ _ _)%E.
459
460 iMod "AU" as "(%vs & (%γs' & Hγs' & %hist3 & %ℓ_head & %ℓ_tail''' & %hpos & %tpos''' & @) & Hclose)".
461 iDestruct (meta_agree with "Hγs Hγs'") as "<- {Hγs'}".
462 iDestruct (mono_list_auth_lb_own_valid with "Hhist● Hhist2◯") as %Hhist23.
463 destruct Hhist23 as [_ Hhist23]. rename Hℓtpos into Hℓtpos3.
464
465 destruct (loc_at hist3 (S tpos)) as [ℓ_tail''''|] eqn:Hrace.
466 * (* Another item has been enqueued in the meantime, so the CAS is poised to fail. *)
467 iDestruct "Hclose" as "[Hclose _]".
468
469 iDestruct (hist_repr_peek_3 with "[$Hrepr]") as "[Hℓ_tail1 Hrepr]".
470 { eapply prefix_lookup_Some; first apply Hℓtpos0''. by apply prefix_of_fmap. }
471 rewrite Hrace /=.
472 wp_cmpxchg_fail.
473 iSpecialize ("Hrepr" with "Hℓ_tail1").
474 iAssert (queue_repr_1 γs ℓ_q vs) with "[$Hhead $Htail $Hhist● $Hhpos● $Hrepr]" as "Hq".
475 { iExists tpos'''. by iFrameNamed. }
476 iMod ("Hclose" with "[$]") as "AU". iModIntro.
477 wp_pures. iApply ("IH" with "Hndata Hnnext AU").
478 * (* This node is still the tail, so the CAS will succeed. *)
479 iDestruct "Hclose" as "[_ Hclose]".
480
481 iAssert ⌜length hist3 = S tpos⌝%I as %Hhist3.
482 { apply loc_at_length in Hrace as Hhist3.
483 iPureIntro. apply loc_at_prefix with (xs':=hist3) in Hℓtpos0''; last done.
484 apply lookup_lt_Some in Hℓtpos0''. rewrite length_fmap in Hℓtpos0''. lia. }
485
486 iDestruct (hist_repr_peek_2 with "[$Hrepr]") as "(%w' & Hℓ_tail3 & Hrepr)".
487 { eapply prefix_lookup_Some; first apply Hℓtpos0''. by apply prefix_of_fmap. }
488 iNamedSuffix "Hℓ_tail3" "_tail3".
489 iPoseProof ("Hrepr" with "[$]") as "Hrepr". clear w.
490
491 iPoseProof (hist_repr_snoc with "[$Hndata $Hnnext] [$Hrepr]") as "[Htnode Henq]".
492 { apply Hhist3. }
493 { eapply prefix_lookup_Some. apply Hℓtpos0''. by apply prefix_of_fmap. }
494 wp_cmpxchg_suc. iSpecialize ("Henq" with "Htnode").
495
496 iMod (mono_list_auth_own_update_app [(ℓ_node, data)] with "Hhist●") as "[Hhist● _]".
497
498 iAssert (queue_repr_1 γs ℓ_q (vs ++ [data])) with "[$Hhead $Htail $Hhist● $Hhpos● $Henq]" as "Hq".
499 { iExists tpos'''. iPureIntro.
500 repeat split; try done.
501 - eapply loc_at_prefix; first done.
502 by apply prefix_app_r.
503 - eapply loc_at_prefix; first done.
504 by apply prefix_app_r.
505 - rewrite drop_app fmap_app -Hvs.
506 f_equal.
507 assert (Hhpos : hpos < length hist3).
508 { apply lookup_lt_Some in Hℓhpos.
509 by rewrite length_fmap in Hℓhpos. }
510 by assert (S hpos - length hist3 = 0) as -> by lia. }
511 iMod ("Hclose" with "[$]") as "HΦ".
512 iModIntro. wp_pures. done.
513 Qed.
514
515 Lemma enqueue_spec (ℓ_q : loc) (data : val) :
516 ⊢ <<{ ∀∀ vs, queue_repr ℓ_q vs }>>
517 enqueue #ℓ_q data @ ∅
518 <<{ queue_repr ℓ_q (vs ++ [data]) | RET #() }>>.
519 Proof.
520 iIntros "%Φ AU". wp_lam. wp_pures.
521 wp_apply (new_node_spec with "[//]") as "%ℓ_node Hnode".
522 awp_apply (set_tail_spec with "[$Hnode]").
523 rewrite /atomic_acc /=. iMod "AU" as "(%vs & Hrepr & Hclose)".
524 iModIntro. iFrame.
525 Qed.
526
527 Lemma try_dequeue_spec (ℓ_q : loc) :
528 ⊢ <<{ ∀∀ vs, queue_repr ℓ_q vs }>>
529 try_dequeue #ℓ_q @ ∅
530 <<{ queue_repr ℓ_q (tail vs) | RET (val_opt_hl (head vs)) }>>.
531 Proof.
532 iIntros "%Φ AU". iLöb as "IH". wp_rec.
533
534 wp_bind (! _)%E.
535 iMod "AU" as "(%vs0 & (%γs & #Hγs & %hist0 & %ℓ_head0 & %ℓ_tail0 & %hpos0 & %tpos0 & @) & [Hclose _])".
536 iDestruct (mono_list_lb_own_get with "Hhist●") as "#Hhist0◯".
537 iDestruct (mono_nat_lb_own_get with "Hhpos●") as "#Hhpos0◯".
538 rename Hℓhpos into Hℓhpos0.
539 wp_load.
540 iMod ("Hclose" with "[$Hhead $Htail $Hhist● $Hhpos● $Hrepr $Hγs]") as "AU".
541 { iExists tpos0. by iFrameNamed. }
542 iModIntro. clear vs0 Hvs tpos0 Hℓtpos ℓ_tail0.
543
544 wp_pures. wp_bind (! _)%E.
545 iMod "AU" as "(%vs1 & (%γs' & Hγs' & %hist1 & %ℓ_head1 & %ℓ_tail1 & %hpos1 & %tpos1 & @) & Hclose)".
546 iDestruct (meta_agree with "Hγs Hγs'") as "<- {Hγs'}".
547 iDestruct (mono_list_lb_own_get with "Hhist●") as "#Hhist1◯".
548 iDestruct (mono_nat_auth_lb_own_valid with "Hhpos● Hhpos0◯") as %Hhpos01.
549 iDestruct (mono_list_auth_lb_own_valid with "Hhist● Hhist0◯") as %Hhist01.
550 destruct Hhpos01 as [_ Hhpos01]. destruct Hhist01 as [_ Hhist01].
551 assert (Hℓhpos0' : loc_at hist1 hpos0 = Some ℓ_head0).
552 { by eapply loc_at_prefix. } clear Hℓhpos0.
553 iDestruct (hist_repr_peek_2 with "[$Hrepr]") as "(%u & @ & Hrepr)"; first done.
554 wp_load.
555 iSpecialize ("Hrepr" with "[$]").
556
557 destruct (loc_at hist1 (S hpos0)) as [ℓ_headS0|] eqn:Hℓ_headS0.
558 - simpl. iDestruct "Hclose" as "[Hclose _]".
559 iMod ("Hclose" with "[$Hhead $Htail $Hhist● $Hhpos● $Hrepr $Hγs]") as "AU".
560 { iExists tpos1. by iFrameNamed. }
561 iModIntro. clear u vs1 Hvs tpos1 Hℓtpos ℓ_tail1.
562
563 wp_pures. wp_bind (! _)%E.
564 iMod "AU" as "(%vs2 & (%γs' & Hγs' & %hist2 & %ℓ_head2 & %ℓ_tail2 & %hpos2 & %tpos2 & @) & Hclose)".
565 iDestruct (meta_agree with "Hγs Hγs'") as "<- {Hγs'}".
566 iDestruct (mono_list_lb_own_get with "Hhist●") as "#Hhist2◯".
567 iDestruct (mono_nat_auth_lb_own_valid with "Hhpos● Hhpos0◯") as %Hhpos02.
568 iDestruct (mono_list_auth_lb_own_valid with "Hhist● Hhist1◯") as %Hhist12.
569 destruct Hhpos02 as [_ Hhpos02]. destruct Hhist12 as [_ Hhist12].
570 assert (Hℓ_headS0' : loc_at hist2 (S hpos0) = Some ℓ_headS0).
571 { by eapply loc_at_prefix. } clear Hℓ_headS0.
572 apply loc_at_val_at_Some in Hℓ_headS0' as Hval_headS0'.
573 destruct Hval_headS0' as [w Hval_headS0'].
574 iDestruct (hist_repr_peek_1 with "[$Hrepr]") as "(@ & Hrepr)"; try done.
575 iDestruct "Hndata" as "#Hndata_head".
576 wp_load.
577
578 iDestruct "Hclose" as "[Hclose _]".
579
580 iSpecialize ("Hrepr" with "[$]").
581 iMod ("Hclose" with "[$Hhead $Htail $Hhist● $Hhpos● $Hrepr $Hγs]") as "AU".
582 { iExists tpos2. by iFrameNamed. }
583 iModIntro.
584 clear vs2 Hvs tpos2 Hℓtpos ℓ_tail2.
585
586 wp_pures.
587
588 wp_bind (CmpXchg _ _ _)%E.
589 iMod "AU" as "(%vs3 & (%γs' & Hγs' & %hist3 & %ℓ_head3 & %ℓ_tail3 & %hpos3 & %tpos3 & @) & Hclose)".
590 iDestruct (meta_agree with "Hγs Hγs'") as "<- {Hγs'}".
591 iDestruct (mono_list_auth_lb_own_valid with "Hhist● Hhist2◯") as %Hhist23.
592 destruct Hhist23 as [_ Hhist23].
593 assert (Hhist13 : hist1 `prefix_of` hist3).
594 { by trans hist2. }
595
596 destruct (decide (ℓ_head0 = ℓ_head3)) as [->|Hhead03].
597 + iDestruct "Hclose" as "[_ Hclose]".
598
599 wp_cmpxchg_suc.
600
601 assert (Hℓhpos0'' : loc_at hist3 hpos0 = Some ℓ_head3).
602 { by eapply loc_at_prefix. } clear Hℓhpos0'.
603 iAssert ⌜hpos0 = hpos3⌝%I as %->.
604 { by iApply (loc_at_inj with "Hrepr"). }
605
606 simplify_eq/=.
607
608 iMod (mono_nat_own_update (S hpos3) with "Hhpos●") as "[Hhpos● _]". { lia. }
609 iMod ("Hclose" with "[$Hhead $Htail $Hhist● $Hhpos● $Hrepr $Hγs]") as "HΦ".
610 { iExists tpos3. iFrameNamed.
611 iPureIntro. repeat split; try done.
612 - by eapply loc_at_prefix.
613 - by rewrite -[S (S _)]Nat.add_1_r -drop_drop [(drop 1 _).*2]fmap_drop. }
614
615 iModIntro. wp_pures.
616
617 assert (Hval_headS0'' : val_at hist3 (S hpos3) = Some w).
618 { by eapply val_at_prefix. } clear Hval_headS0'.
619 unfold val_at in Hval_headS0''.
620 rewrite -[S hpos3]Nat.add_0_r -lookup_drop -fmap_drop /= -head_lookup in Hval_headS0''.
621 by rewrite Hval_headS0'' /=.
622
623 + iDestruct "Hclose" as "[Hclose _]".
624
625 wp_cmpxchg_fail.
626
627 iMod ("Hclose" with "[$Hhead $Htail $Hhist● $Hhpos● $Hrepr $Hγs]") as "AU".
628 { iExists tpos3. by iFrameNamed. }
629
630 iModIntro. wp_pures. iApply ("IH" with "AU").
631 - apply loc_at_length in Hℓ_headS0 as Hhistlen.
632 rewrite drop_ge /= in Hvs; last lia. destruct vs1; try done.
633 simplify_eq/=.
634
635 iDestruct "Hclose" as "[_ Hclose]".
636 iMod ("Hclose" with "[$Hhead $Htail $Hhist● $Hhpos● $Hrepr $Hγs]") as "HΦ".
637 { iExists tpos1. iFrameNamed. iPureIntro.
638 rewrite drop_ge //=. lia. }
639
640 iModIntro. wp_pures. iApply "HΦ".
641 Qed.
642
643End basic_queue.
644
645Definition basic_queue `{!heapGS Σ, !basic_queueG Σ} : basic_queue_spec.basic_queue Σ.
646Proof.
647 refine {| basic_queue_spec.new_spec := new_spec;
648 basic_queue_spec.enqueue_spec := enqueue_spec;
649 basic_queue_spec.try_dequeue_spec := try_dequeue_spec |}.
650Defined.
651
652#[global] Typeclasses Opaque queue_repr.