-
Notifications
You must be signed in to change notification settings - Fork 2
/
increment.v
106 lines (93 loc) · 3.68 KB
/
increment.v
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
From iris.base_logic.lib Require Export invariants.
From iris.program_logic Require Export atomic.
From iris.proofmode Require Import tactics.
From iris.heap_lang Require Import proofmode notation atomic_heap par.
From iris.bi.lib Require Import fractional.
Set Default Proof Using "Type".
(** Show that implementing fetch-and-add on top of CAS preserves logical
atomicity. *)
Section increment.
Context `{!heapG Σ} {aheap: atomic_heap Σ}.
Import atomic_heap.notation.
Definition incr: val :=
rec: "incr" "l" :=
let: "oldv" := !"l" in
if: CAS "l" "oldv" ("oldv" + #1)
then "oldv" (* return old value if success *)
else "incr" "l".
Lemma incr_spec (l: loc) :
<<< ∀ (v : Z), l ↦ #v >>> incr #l @ ⊤ <<< l ↦ #(v + 1), RET #v >>>.
Proof.
iApply wp_atomic_intro. iIntros (Φ) "AU". iLöb as "IH". wp_let.
wp_apply load_spec; first by iAccu.
(* Prove the atomic update for load *)
iAuIntro. iApply (aacc_aupd_abort with "AU"); first done.
iIntros (x) "H↦". iAaccIntro with "H↦"; first by eauto with iFrame.
iIntros "$ !> AU !> _".
(* Now go on *)
wp_let. wp_op. wp_bind (CAS _ _ _)%I.
wp_apply cas_spec; [done|iAccu|].
(* Prove the atomic update for CAS *)
iAuIntro. iApply (aacc_aupd with "AU"); first done.
iIntros (x') "H↦". iAaccIntro with "H↦"; first by eauto with iFrame.
iIntros "H↦ !>".
destruct (decide (#x' = #x)) as [[= ->]|Hx].
- iRight. iFrame. iIntros "HΦ !> _".
wp_if. by iApply "HΦ".
- iLeft. iFrame. iIntros "AU !> _".
wp_if. iApply "IH". done.
Qed.
Definition weak_incr: val :=
rec: "weak_incr" "l" :=
let: "oldv" := !"l" in
"l" <- ("oldv" + #1);;
"oldv" (* return old value *).
(* TODO: Generalize to q and 1-q, based on some theory for a "maybe-mapsto"
connective that works on [option Qp] (the type of 1-q). *)
Lemma weak_incr_spec (l: loc) (v : Z) :
l ↦{1/2} #v -∗
<<< ∀ (v' : Z), l ↦{1/2} #v' >>>
weak_incr #l @ ⊤
<<< ⌜v = v'⌝ ∗ l ↦ #(v + 1), RET #v >>>.
Proof.
iIntros "Hl". iApply wp_atomic_intro. iIntros (Φ) "AU". wp_let.
wp_apply (atomic_wp_seq $! (load_spec _) with "Hl").
iIntros "Hl". wp_let. wp_op.
wp_apply store_spec; first by iAccu.
(* Prove the atomic update for store *)
iAuIntro. iApply (aacc_aupd_commit with "AU"); first done.
iIntros (x) "H↦".
iDestruct (mapsto_agree with "Hl H↦") as %[= <-].
iCombine "Hl" "H↦" as "Hl". iAaccIntro with "Hl".
{ iIntros "[$ $]"; eauto. }
iIntros "$ !>". iSplit; first done.
iIntros "HΦ !> _". wp_seq. done.
Qed.
End increment.
Section increment_client.
Context `{!heapG Σ, !spawnG Σ}.
Existing Instance primitive_atomic_heap.
Definition incr_client : val :=
λ: "x",
let: "l" := ref "x" in
incr "l" ||| incr "l".
Lemma incr_client_safe (x: Z):
WP incr_client #x {{ _, True }}%I.
Proof using Type*.
wp_let. wp_alloc l as "Hl". wp_let.
iMod (inv_alloc nroot _ (∃x':Z, l ↦ #x')%I with "[Hl]") as "#Hinv"; first eauto.
(* FIXME: I am only using persistent stuff, so I should be allowed
to move this to the persisten context even without the additional □. *)
iAssert (□ WP incr #l {{ _, True }})%I as "#Aupd".
{ iAlways. wp_apply incr_spec; first by iAccu. clear x.
iAuIntro. iInv nroot as (x) ">H↦". iAaccIntro with "H↦"; first by eauto 10.
iIntros "H↦ !>". iSplitL "H↦"; first by eauto 10.
(* The continuation: From after the atomic triple to the postcondition of the WP *)
done.
}
wp_apply wp_par.
- iAssumption.
- iAssumption.
- iIntros (??) "_ !>". done.
Qed.
End increment_client.