From 0e7e1e0770efef65f19112e1d16a6d9b6596e785 Mon Sep 17 00:00:00 2001
From: Dan Frumin <dfrumin@cs.ru.nl>
Date: Wed, 6 May 2020 16:12:12 +0200
Subject: [PATCH] Ticket lock refinement using HOCAP-style specs

---
 _CoqProject                               |   1 +
 theories/examples/ticket_lock.v           |   4 +-
 theories/experimental/hocap/counter.v     |  69 +++++++++--
 theories/experimental/hocap/ticket_lock.v | 137 ++++++++++++++++++++++
 4 files changed, 199 insertions(+), 12 deletions(-)
 create mode 100644 theories/experimental/hocap/ticket_lock.v

diff --git a/_CoqProject b/_CoqProject
index fffd12e..2a786e2 100644
--- a/_CoqProject
+++ b/_CoqProject
@@ -63,3 +63,4 @@ theories/experimental/helping/offers.v
 theories/experimental/helping/helping_stack.v
 
 theories/experimental/hocap/counter.v
+theories/experimental/hocap/ticket_lock.v
diff --git a/theories/examples/ticket_lock.v b/theories/examples/ticket_lock.v
index 92515f0..c5a8257 100644
--- a/theories/examples/ticket_lock.v
+++ b/theories/examples/ticket_lock.v
@@ -4,7 +4,7 @@ From stdpp Require Import sets.
 From iris.algebra Require Export auth gset excl.
 From iris.base_logic Require Import auth.
 From reloc Require Import reloc lib.lock lib.counter.
-From iris.heap_lang.lib Require Import ticket_lock.
+From iris.heap_lang.lib Require Export ticket_lock.
 
 (* A different `acquire` funciton to showcase the atomic rule for FG_increment *)
 Definition acquire : val := λ: "lk",
@@ -13,6 +13,8 @@ Definition acquire : val := λ: "lk",
 (* A different `release` function to showcase the rule for wkincr *)
 Definition release : val := λ: "lk", wkincr (Fst "lk").
 
+Definition newlock : val := ticket_lock.newlock.
+
 Definition lrel_lock `{relocG Σ} : lrel Σ :=
   ∃ A, (() → A) * (A → ()) * (A → ()).
 
diff --git a/theories/experimental/hocap/counter.v b/theories/experimental/hocap/counter.v
index 97404a8..37a1839 100644
--- a/theories/experimental/hocap/counter.v
+++ b/theories/experimental/hocap/counter.v
@@ -1,13 +1,11 @@
 (* ReLoC -- Relational logic for fine-grained concurrency *)
 (** HOCAP-style specifications for the concurrent counter *)
 From reloc Require Export reloc.
-From reloc.lib Require Export counter.
+From reloc.lib Require Export counter lock.
 From iris.algebra Require Export auth frac excl.
 From iris.bi.lib Require Export fractional.
 From iris.base_logic.lib Require Export auth.
 
-Definition wk_incr : val := λ: "c", "c" <- !"c" + #1.
-
 Class cnt_hocapG Σ := CntG {
     cnt_hocapG_inG :> authG Σ (optionUR (prodR fracR (agreeR natO)));
 }.
@@ -107,13 +105,62 @@ Section cnt_spec.
     iModIntro. iExists _; iFrame. iExists _; iSplit; eauto with iFrame.
   Qed.
 
-  Lemma wk_incr_l E c γ K e A q n :
+
+  Lemma wkincr_l_2 E c γ K e A :
+    E ## ↑ N →
+    Cnt c γ -∗
+    (∀ n, cnt_auth γ n ={⊤∖↑N}=∗ cnt_auth γ n ∗ ∀ m,
+       (cnt_auth γ m ={⊤∖↑N, ⊤∖↑N∖E}=∗
+          cnt_auth γ (n+1) ∗ REL fill K (of_val #()) << e @ (⊤∖E): A)) -∗
+    REL fill K (wkincr c) << e : A.
+  Proof.
+    iIntros (?).
+    iDestruct 1 as (l ->) "#Hcnt". iIntros "Hvs".
+    rel_rec_l. rel_load_l_atomic.
+    iInv N as (n1) ">[Hl Ha]" "Hcl". iModIntro.
+    iExists #n1. iFrame "Hl"; iIntros "!> Hl".
+    iMod ("Hvs" with "Ha") as "[Ha Hvs]".
+    iMod ("Hcl" with "[Hl Ha]") as "_".
+    { iNext. iExists _; by iFrame. }
+    rel_pures_l. rel_store_l_atomic.
+    iMod (inv_acc_strong with "Hcnt") as "[>Hcnt' Hcl]"; first by solve_ndisj.
+    iDestruct "Hcnt'" as (n2) "[Hl Ha]".
+    iModIntro. iExists _. iFrame "Hl". iIntros "!> Hl".
+    (* iDestruct (cnt_agree_2 with "Ha Hc") as %->. *)
+    iMod ("Hvs" with "Ha") as "(Ha & Href)".
+    iMod ("Hcl" with "[Ha Hl]") as "_".
+    { iNext. assert ((Z.of_nat n1 + 1)%Z = Z.of_nat (n1 + 1)) as -> by lia.
+      iExists _. by iFrame. }
+    assert (⊤ ∖ ↑N ∖ E = ⊤ ∖ E ∖ ↑N) as -> by set_solver.
+    rewrite -union_difference_L; last set_solver.
+    done.
+  Qed.
+
+  Lemma wkincr_l E c γ K e A q n :
+    E ## ↑ N →
+    Cnt c γ -∗
+    cnt γ q n -∗
+    (cnt_auth γ n ∗ cnt γ q n ={⊤∖↑N, ⊤∖↑N∖E}=∗
+     cnt_auth γ (n+1) ∗ REL fill K (of_val #()) << e @ (⊤∖E): A) -∗
+    REL fill K (wkincr c) << e : A.
+  Proof.
+    iIntros (?) "#Hcnt Hn Hvs".
+    iApply wkincr_l_2; try done.
+    iIntros (n1) "Ha".
+    iDestruct (cnt_agree_2 with "Ha Hn") as %->.
+    iModIntro. iFrame "Ha". iIntros (m) "Ha".
+    iDestruct (cnt_agree_2 with "Ha Hn") as %->.
+    iMod ("Hvs" with "[$Ha $Hn]") as "(Ha & Hvs)".
+    iModIntro. by iFrame.
+  Qed.
+
+  Lemma wkincr_l_alt E c γ K e A q n :
     E ## ↑ N →
     Cnt c γ -∗
     cnt γ q n -∗
     (cnt_auth γ n ∗ cnt γ q n ={⊤∖↑N, ⊤∖↑N∖E}=∗
-     cnt_auth γ (n+1) ∗ cnt γ q (n+1) ∗ REL fill K (of_val #()) << e @ (⊤∖E): A) -∗
-    REL fill K (wk_incr c) << e : A.
+     cnt_auth γ (n+1) ∗ REL fill K (of_val #()) << e @ (⊤∖E): A) -∗
+    REL fill K (wkincr c) << e : A.
   Proof.
     iIntros (?).
     iDestruct 1 as (l ->) "#Hcnt". iIntros "Hc Hvs".
@@ -128,7 +175,7 @@ Section cnt_spec.
     iDestruct "Hcnt'" as (m) "[Hl Ha]".
     iDestruct (cnt_agree_2 with "Ha Hc") as %->.
     iModIntro. iExists _. iFrame "Hl". iIntros "!> Hl".
-    iMod ("Hvs" with "[$Ha $Hc]") as "(Ha & Hc & Href)".
+    iMod ("Hvs" with "[$Ha $Hc]") as "(Ha & Href)".
     iMod ("Hcl" with "[Ha Hl]") as "_".
     { iNext. assert ((Z.of_nat n + 1)%Z = Z.of_nat (n + 1)) as -> by lia.
       iExists _. by iFrame. }
@@ -218,7 +265,7 @@ Section refinement.
 
   Lemma incr_refinement c γ lk l :
     Cnt N c γ -∗
-    inv N2 (∃ m, lock.is_locked_r lk false ∗ cnt γ 1 m ∗ l ↦ₛ #m)%I -∗
+    inv N2 (∃ m, is_locked_r lk false ∗ cnt γ 1 m ∗ l ↦ₛ #m)%I -∗
     REL FG_increment c << CG_increment #l lk : interp TNat [].
   Proof.
     iIntros "#HCnt #HI".
@@ -240,7 +287,7 @@ Section refinement.
 
   Lemma read_refinement c γ lk l :
     Cnt N c γ -∗
-    inv N2 (∃ m, lock.is_locked_r lk false ∗ cnt γ 1 m ∗ l ↦ₛ #m)%I -∗
+    inv N2 (∃ m, is_locked_r lk false ∗ cnt γ 1 m ∗ l ↦ₛ #m)%I -∗
     REL counter_read c << counter_read #l : interp TNat [].
   Proof.
     iIntros "#HCnt #HI".
@@ -264,7 +311,7 @@ Section refinement.
     iApply refines_arrow_val.
     iAlways. iIntros (? ?) "_"; simplify_eq/=.
     rel_rec_l. rel_rec_r.
-    rel_apply_r lock.refines_newlock_r; auto.
+    rel_apply_r refines_newlock_r; auto.
     iIntros (lk) "Hlk".
     repeat rel_pure_r.
     rel_alloc_r c' as "Hcnt'".
@@ -273,7 +320,7 @@ Section refinement.
     iMod (Cnt_alloc N _ 0%nat with "Hcnt") as (γ) "[#HCnt Hc]".
 
     (* establishing the invariant *)
-    iMod (inv_alloc N2 _ (∃ m, lock.is_locked_r lk false ∗ cnt γ 1 m ∗ c' ↦ₛ #m)%I
+    iMod (inv_alloc N2 _ (∃ m, is_locked_r lk false ∗ cnt γ 1 m ∗ c' ↦ₛ #m)%I
          with "[-]") as "#Hinv".
     { iNext. iExists 0%nat. by iFrame. }
     (* TODO: here we have to do /exactly/ 4 steps.
diff --git a/theories/experimental/hocap/ticket_lock.v b/theories/experimental/hocap/ticket_lock.v
new file mode 100644
index 0000000..d0f2058
--- /dev/null
+++ b/theories/experimental/hocap/ticket_lock.v
@@ -0,0 +1,137 @@
+(* ReLoC -- Relational logic for fine-grained concurrency *)
+(** Ticket lock ≼ spin lock refinement using HOCAP-style specs for the counter *)
+From reloc Require Export reloc.
+From reloc.experimental Require Export hocap.counter.
+From reloc.lib Require Import lock.
+From reloc.examples Require Import ticket_lock.
+Module spin_lock := reloc.lib.lock.
+
+Section refinement.
+  Context `{!relocG Σ, !tlockG Σ, !cnt_hocapG Σ}.
+
+  (** * Invariants and abstracts for them *)
+  Definition lockInv (γlo γln : gname) (γ : gname) (l' : val) : iProp Σ :=
+    (∃ (o n : nat) (b : bool), cnt γlo 1 o ∗ cnt γln 1 n
+   ∗ issuedTickets γ n ∗ is_locked_r l' b
+   ∗ if b then ticket γ o else True)%I.
+
+  Instance ifticket_timeless (b : bool) γ o : Timeless (if b then ticket γ o else True%I).
+  Proof. destruct b; apply _. Qed.
+  Instance lockInv_timeless lo ln γ l' : Timeless (lockInv lo ln γ l').
+  Proof. apply _. Qed.
+
+  Definition N := nroot.@"locked".
+
+  Definition lockInt : lrel Σ := LRel (λ v1 v2,
+    (∃ (γln γlo : gname) (co cn : val) (γ : gname),
+        ⌜v1 = (co, cn)%V⌝
+      ∗ Cnt (N.@"cnt1") cn γln
+      ∗ Cnt (N.@"cnt2") co γlo
+      ∗ inv (N.@"lock") (lockInv γlo γln γ v2)))%I.
+
+  Local Instance lockInt_persistent w1 w2 : Persistent (lockInt w1 w2).
+  Proof. apply _. Qed.
+
+  Lemma wait_loop_refinement (co cn : val) (γlo γln γ : gname) (l' : val) (m : nat) :
+    inv (N.@"lock") (lockInv γlo γln γ l') -∗
+    Cnt (N.@"cnt1") cn γln -∗
+    Cnt (N.@"cnt2") co γlo -∗
+    ticket γ m -∗
+    REL wait_loop #m (co, cn)%V << spin_lock.acquire l' : ().
+  Proof.
+    iIntros "#Hinv #Hcntn #Hcnto Hticket".
+    iLöb as "IH". rel_rec_l.
+    rel_pures_l.
+    rel_apply_l (cnt_read_l _ (↑N.@"lock") with "Hcnto"); first by solve_ndisj.
+    iIntros (o) "Hlo".
+    iMod (inv_acc_strong with "Hinv") as "[HH Hcl]"; first solve_ndisj.
+    iDestruct "HH" as (o' n b) "(>Hlo' & >Hln & >Hissued & >[Hl' Hbticket])".
+    iDestruct (cnt_agree_2 with "Hlo Hlo'") as %<-.
+    iModIntro. iFrame. rel_pures_l.
+    case_decide; simplify_eq/=; rel_pures_l; last first.
+    (* Whether the ticket is called out *)
+    - iMod ("Hcl" with "[-Hticket]") as "_".
+      { iNext. iExists _,_,_; by iFrame. }
+      rewrite -union_difference_L; last done.
+      by iApply "IH".
+    - destruct b.
+      { iDestruct (ticket_nondup with "Hticket Hbticket") as %[]. }
+      rel_apply_r (refines_acquire_r with "Hl'").
+      iIntros "Hl'".
+      iMod ("Hcl" with "[-]") as "_".
+      { iNext; iExists _,_,_; iFrame. }
+      rewrite -union_difference_L; last done.
+      rel_values.
+  Qed.
+
+  Lemma acquire_refinement :
+    ⊢ REL acquire << spin_lock.acquire : (lockInt → ()).
+  Proof.
+    rel_arrow_val.
+    iIntros (? l') "/= #Hl".
+    iDestruct "Hl" as (γln γlo lo ln γ) "(-> & Hcntn & Hcnto & Hin)".
+    rel_rec_l. rel_pures_l.
+    rel_apply_l (cnt_increment_l _ ∅ with "Hcntn"); first by set_solver.
+    (* the viewshift *)
+    iIntros (n) "Hln".
+    iInv (N.@"lock") as (o n' b) "(Hlo & >Hln' & >Hissued & >Hb)" "Hcl".
+    iDestruct (cnt_agree_2 with "Hln Hln'") as %<-.
+    iMod (issueNewTicket with "Hissued") as "[Hissued Hticket]".
+    iMod (cnt_update (n+1) with "Hln Hln'") as "[Hln Hln']".
+    iMod ("Hcl" with "[Hissued Hlo Hln' Hb]") as "_".
+    { iNext. iExists _,_,_; iFrame. assert (n+1 = S n) as -> by lia. done. }
+    iFrame. rewrite !difference_empty_L. iModIntro.
+    rel_pures_l. by iApply wait_loop_refinement.
+  Qed.
+
+  Lemma release_refinement :
+    ⊢ REL release << spin_lock.release : (lockInt → ()).
+  Proof.
+    rel_arrow_val.
+    iIntros (? l') "/= #Hl".
+    iDestruct "Hl" as (γln γlo lo ln γ) "(-> & Hcntn & Hcnto & Hinv)".
+    rel_rec_l. rel_pures_l.
+    rel_apply_l (wkincr_l_2 _ (↑N.@"lock") with "Hcnto"); first solve_ndisj.
+    iIntros (n) "Hlo". iModIntro. iFrame. iIntros (m) "Hlo".
+    iMod (inv_acc_strong with "Hinv") as "[HH Hcl]"; first solve_ndisj.
+    iDestruct "HH" as (o' n2 b) "(>Hlo' & >Hln & >Hissued & >[Hl' Hbticket])".
+    iMod (cnt_update (n+1) with "Hlo Hlo'") as "[Hlo Hlo']".
+    iModIntro. iFrame.
+    rel_apply_r (refines_release_r with "Hl'"). iIntros "Hl'".
+    iMod ("Hcl" with "[-]") as "_".
+    { iNext. rewrite {2}/lockInv.
+      iExists _,_,_. by iFrame. }
+    rewrite -union_difference_L; last done.
+    by rel_values.
+  Qed.
+
+  Lemma newlock_refinement :
+    ⊢ REL newlock << spin_lock.newlock : (() → lockInt).
+  Proof.
+    rel_arrow_val.
+    iIntros (? ?) "[% %]"; subst.
+    rel_rec_l. rel_alloc_l lo as "Hlo".
+    rel_alloc_l ln as "Hln". rel_pures_l.
+    rel_apply_r refines_newlock_r. iIntros (l') "Hl'".
+    iMod (Cnt_alloc (N.@"cnt2") _ 0 with "Hln") as (γln) "[#Hc1 Hln]".
+    iMod (Cnt_alloc (N.@"cnt1") _ 0 with "Hlo") as (γlo) "[#Hc2 Hlo]".
+    iMod newIssuedTickets as (γ) "Hγ".
+    iMod (inv_alloc (N.@"lock") _ (lockInv γln γlo γ l') with "[-]") as "#Hinv".
+    { iNext. iExists 0%nat,0%nat,_. iFrame. }
+    rel_values. iModIntro. iExists _,_,_,_,_. iSplit; eauto with iFrame.
+  Qed.
+
+  Lemma ticket_lock_refinement Δ :
+    ⊢ REL (newlock, acquire, release)
+            <<
+           (spin_lock.newlock, spin_lock.acquire, spin_lock.release) : interp lockT Δ.
+  Proof.
+    iApply (refines_exists lockInt).
+    repeat iApply refines_pair; simpl.
+    - by iApply newlock_refinement.
+    - by iApply acquire_refinement.
+    - by iApply release_refinement.
+  Qed.
+
+End refinement.
+
-- 
GitLab