counter.v 5.48 KB
Newer Older
1 2
(* This file contains a formalization of the monotone counter, but with an
explicit contruction of the monoid, as we have also done in the proof mode
Ralf Jung's avatar
Ralf Jung committed
3 4
paper. This should simplify explaining and understanding what is happening.
A version that uses the authoritative monoid and natural number monoid
5 6 7 8
under max can be found in `heap_lang/lib/counter.v`. *)
From iris.program_logic Require Export weakestpre.
From iris.heap_lang Require Export lang.
From iris.program_logic Require Export hoare.
9
From iris.proofmode Require Import tactics.
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
From iris.heap_lang Require Import proofmode notation.
Import uPred.

Definition newcounter : val := λ: <>, ref #0.
Definition inc : val :=
  rec: "inc" "l" :=
    let: "n" := !"l" in
    if: CAS "l" "n" (#1 + "n") then #() else "inc" "l".
Definition read : val := λ: "l", !"l".
Global Opaque newcounter inc read.

(** The CMRA we need. *)
Inductive M := Auth : nat  M | Frag : nat  M | Bot.

Section M.
  Arguments cmra_op _ !_ !_/.
  Arguments op _ _ !_ !_/.
  Arguments core _ _ !_/.

  Canonical Structure M_C : cofeT := leibnizC M.

  Instance M_valid : Valid M := λ x, x  Bot.
  Instance M_op : Op M := λ x y,
    match x, y with
    | Auth n, Frag j | Frag j, Auth n => if decide (j  n)%nat then Auth n else Bot
    | Frag i, Frag j => Frag (max i j)
    | _, _ => Bot
    end.
  Instance M_pcore : PCore M := λ x,
    Some match x with Auth j | Frag j => Frag j | _ => Bot end.
  Instance M_empty : Empty M := Frag 0.

  Definition M_ra_mixin : RAMixin M.
  Proof.
    apply ra_total_mixin; try solve_proper || eauto.
    - intros [n1|i1|] [n2|i2|] [n3|i3|];
        repeat (simpl; case_decide); f_equal/=; lia.
    - intros [n1|i1|] [n2|i2|]; repeat (simpl; case_decide); f_equal/=; lia.
    - intros [n|i|]; repeat (simpl; case_decide); f_equal/=; lia.
    - by intros [n|i|].
    - intros [n1|i1|] y [[n2|i2|] ?]; exists (core y); simplify_eq/=;
        repeat (simpl; case_decide); f_equal/=; lia.
    - intros [n1|i1|] [n2|i2|]; simpl; by try case_decide.
  Qed.
  Canonical Structure M_R : cmraT := discreteR M M_ra_mixin.
  Definition M_ucmra_mixin : UCMRAMixin M.
  Proof.
    split; try (done || apply _).
    intros [?|?|]; simpl; try case_decide; f_equal/=; lia.
  Qed.
  Canonical Structure M_UR : ucmraT := discreteUR M M_ra_mixin M_ucmra_mixin.

  Global Instance frag_persistent n : Persistent (Frag n).
  Proof. by constructor. Qed.
  Lemma auth_frag_valid j n :  (Auth n  Frag j)  (j  n)%nat.
  Proof. simpl. case_decide. done. by intros []. Qed.
  Lemma auth_frag_op (j n : nat) : (j  n)%nat  Auth n = Auth n  Frag j.
  Proof. intros. by rewrite /= decide_True. Qed.

  Lemma M_update n : Auth n ~~> Auth (S n).
  Proof.
    apply cmra_discrete_update=>-[m|j|] /= ?; repeat case_decide; done || lia.
  Qed.
End M.

Class counterG Σ := CounterG { counter_tokG :> inG Σ M_UR }.
76 77 78
Definition counterΣ : gFunctors := #[GFunctor (constRF M_UR)].
Instance subG_counterΣ {Σ} : subG counterΣ Σ  counterG Σ.
Proof. intros [?%subG_inG _]%subG_inv. split; apply _. Qed.
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97

Section proof.
Context `{!heapG Σ, !counterG Σ}.
Implicit Types l : loc.

Definition I (γ : gname) (l : loc) : iProp Σ :=
  ( c : nat, l  #c  own γ (Auth c))%I.

Definition C (l : loc) (n : nat) : iProp Σ :=
  ( N γ, heapN  N  heap_ctx  inv N (I γ l)  own γ (Frag n))%I.

(** The main proofs. *)
Global Instance C_persistent l n : PersistentP (C l n).
Proof. apply _. Qed.

Lemma newcounter_spec N :
  heapN  N 
  heap_ctx  {{ True }} newcounter #() {{ v,  l, v = #l  C l 0 }}.
Proof.
98
  iIntros (?) "#Hh !# _ /=". rewrite -wp_fupd /newcounter /=. wp_seq. wp_alloc l as "Hl".
99
  iMod (own_alloc (Auth 0)) as (γ) "Hγ"; first done.
100
  rewrite (auth_frag_op 0 0) //; iDestruct "Hγ" as "[Hγ Hγf]".
101
  iMod (inv_alloc N _ (I γ l) with "[Hl Hγ]") as "#?".
102
  { iIntros "!>". iExists 0%nat. by iFrame. }
103
  iModIntro. rewrite /C; eauto 10.
104 105 106 107 108 109 110 111
Qed.

Lemma inc_spec l n :
  {{ C l n }} inc #l {{ v, v = #()  C l (S n) }}.
Proof.
  iIntros "!# Hl /=". iLöb as "IH". wp_rec.
  iDestruct "Hl" as (N γ) "(% & #Hh & #Hinv & Hγf)".
  wp_bind (! _)%E; iInv N as (c) "[Hl Hγ]" "Hclose".
112 113
  wp_load. iMod ("Hclose" with "[Hl Hγ]"); [iNext; iExists c; by iFrame|].
  iModIntro. wp_let. wp_op.
114 115 116
  wp_bind (CAS _ _ _). iInv N as (c') ">[Hl Hγ]" "Hclose".
  destruct (decide (c' = c)) as [->|].
  - iCombine "Hγ" "Hγf" as "Hγ".
117
    iDestruct (own_valid with "Hγ") as %?%auth_frag_valid; rewrite -auth_frag_op //.
118
    iMod (own_update with "Hγ") as "Hγ"; first apply M_update.
119
    rewrite (auth_frag_op (S n) (S c)); last lia; iDestruct "Hγ" as "[Hγ Hγf]".
120
    wp_cas_suc. iMod ("Hclose" with "[Hl Hγ]").
121
    { iNext. iExists (S c). rewrite Nat2Z.inj_succ Z.add_1_l. by iFrame. }
122
    iModIntro. wp_if. rewrite {3}/C; eauto 10.
123
  - wp_cas_fail; first (intros [=]; abstract omega).
124 125
    iMod ("Hclose" with "[Hl Hγ]"); [iNext; iExists c'; by iFrame|].
    iModIntro. wp_if. iApply ("IH" with "[Hγf]"). rewrite {3}/C; eauto 10.
126 127 128 129 130 131
Qed.

Lemma read_spec l n :
  {{ C l n }} read #l {{ v,  m : nat,  (v = #m  n  m)  C l m }}.
Proof.
  iIntros "!# Hl /=". iDestruct "Hl" as (N γ) "(% & #Hh & #Hinv & Hγf)".
132
  rewrite /read /=. wp_let. iInv N as (c) "[Hl Hγ]" "Hclose". wp_load.
133
  iDestruct (own_valid γ (Frag n  Auth c) with "[-]") as % ?%auth_frag_valid.
134 135
  { iApply own_op. by iFrame. }
  rewrite (auth_frag_op c c); last lia; iDestruct "Hγ" as "[Hγ Hγf']".
136 137
  iMod ("Hclose" with "[Hl Hγ]"); [iNext; iExists c; by iFrame|].
  iModIntro; rewrite /C; eauto 10 with omega.
138 139
Qed.
End proof.