Skip to content
Snippets Groups Projects
channel.v 13.3 KiB
Newer Older
(** This file contains the definition of the channels, encoded as a pair of
lock-protected buffers, and their primitive proof rules. Moreover:

- It defines the connective [c ↣ prot] for ownership of channel endpoints,
  which describes that channel endpoint [c] adheres to protocol [prot].
- It proves Actris's specifications of [send] and [recv] w.r.t. dependent
  separation protocols.

An encoding of the usual (binary) choice connectives [prot1 <{Q1}+{Q2}> prot2]
and [prot1 <{Q1}&{Q2}> prot2], inspired by session types, is also included in
this file.
Robbert Krebbers's avatar
Robbert Krebbers committed

In this file we define the three message-passing connectives:
- [new_chan] creates references to two empty buffers and a lock, and returns a
  pair of endpoints, where the order of the two references determines the
  polarity of the endpoints.
- [send] takes an endpoint and adds an element to the first buffer.
- [recv] performs a busy loop until there is something in the second buffer,
  which it pops and returns, locking during each peek.

It is additionaly shown that the channel ownership [c ↣ prot] is closed under
the subprotocol relation [⊑] *)
Robbert Krebbers's avatar
Robbert Krebbers committed
From iris.heap_lang Require Export lifting notation.
From iris.heap_lang Require Import proofmode.
From iris.heap_lang.lib Require Import spin_lock.
From actris.channel Require Export proto.
From actris.utils Require Import llist skip.
Robbert Krebbers's avatar
Robbert Krebbers committed
(** * The definition of the message-passing connectives *)
Definition new_chan : val :=
     let: "l" := lnil #() in
     let: "r" := lnil #() in
     let: "lk" := newlock #() in
Robbert Krebbers's avatar
Robbert Krebbers committed
     ((("l","r"),"lk"), (("r","l"),"lk")).
Definition start_chan : val := λ: "f",
  let: "cc" := new_chan #() in
  Fork ("f" (Snd "cc"));; Fst "cc".

Robbert Krebbers's avatar
Robbert Krebbers committed
  λ: "c" "v",
    let: "lk" := Snd "c" in
    acquire "lk";;
Robbert Krebbers's avatar
Robbert Krebbers committed
    let: "l" := Fst (Fst "c") in
    skipN (llength (Snd (Fst "c")));; (* "Ghost" operation for later stripping *)
    release "lk".
Robbert Krebbers's avatar
Robbert Krebbers committed
  λ: "c",
    let: "lk" := Snd "c" in
    acquire "lk";;
Robbert Krebbers's avatar
Robbert Krebbers committed
    let: "l" := Snd (Fst "c") in
    let: "ret" := if: lisnil "l" then NONE else SOME (lpop "l") in
Robbert Krebbers's avatar
Robbert Krebbers committed
  rec: "go" "c" :=
    match: try_recv "c" with
Robbert Krebbers's avatar
Robbert Krebbers committed
    | NONE => "go" "c"
Robbert Krebbers's avatar
Robbert Krebbers committed
(** * Setup of Iris's cameras *)
Class chanG Σ := {
  chanG_lockG :> lockG Σ;
  chanG_protoG :> protoG Σ val;
Definition chanΣ : gFunctors := #[ lockΣ; protoΣ val ].
Instance subG_chanΣ {Σ} : subG chanΣ Σ  chanG Σ.
Proof. solve_inG. Qed.

Record chan_name := ChanName {
  chan_lock_name : gname;
  chan_proto_name : proto_name;
}.
Instance chan_name_inhabited : Inhabited chan_name :=
  populate (ChanName inhabitant inhabitant).
Instance chan_name_eq_dec : EqDecision chan_name.
Proof. solve_decision. Qed.
Instance chan_name_countable : Countable chan_name.
Proof.
 refine (inj_countable (λ '(ChanName γl γr), (γl,γr))
   (λ '(γl, γr), Some (ChanName γl γr)) _); by intros [].
Qed.

(** * Definition of the mapsto connective *)
Notation iProto Σ := (iProto Σ val).
Robbert Krebbers's avatar
Robbert Krebbers committed
Notation iMsg Σ := (iMsg Σ val).

Definition iProto_mapsto_def `{!heapG Σ, !chanG Σ}
    (c : val) (p : iProto Σ) : iProp Σ :=
   γ s (l r : loc) (lk : val),
     c = ((#(side_elim s l r), #(side_elim s r l)), lk)%V  
Robbert Krebbers's avatar
Robbert Krebbers committed
    is_lock (chan_lock_name γ) lk ( vsl vsr,
      llist internal_eq l vsl 
      llist internal_eq r vsr 
      iProto_ctx (chan_proto_name γ) vsl vsr) 
    iProto_own (chan_proto_name γ) s p.
Definition iProto_mapsto_aux : seal (@iProto_mapsto_def). by eexists. Qed.
Definition iProto_mapsto := iProto_mapsto_aux.(unseal).
Definition iProto_mapsto_eq :
  @iProto_mapsto = @iProto_mapsto_def := iProto_mapsto_aux.(seal_eq).
Arguments iProto_mapsto {_ _ _} _ _%proto.
Instance: Params (@iProto_mapsto) 4 := {}.
Notation "c ↣ p" := (iProto_mapsto c p)
  (at level 20, format "c  ↣  p").

Robbert Krebbers's avatar
Robbert Krebbers committed
Definition iProto_choice {Σ} (a : action) (P1 P2 : iProp Σ)
    (p1 p2 : iProto Σ) : iProto Σ :=
Robbert Krebbers's avatar
Robbert Krebbers committed
  (<a @ (b : bool)> MSG #b {{ if b then P1 else P2 }}; if b then p1 else p2)%proto.
Typeclasses Opaque iProto_choice.
Arguments iProto_choice {_} _ _%I _%I _%proto _%proto.
Instance: Params (@iProto_choice) 2 := {}.
Infix "<{ P1 }+{ P2 }>" := (iProto_choice Send P1 P2) (at level 85) : proto_scope.
Infix "<{ P1 }&{ P2 }>" := (iProto_choice Recv P1 P2) (at level 85) : proto_scope.
Infix "<+{ P2 }>" := (iProto_choice Send True P2) (at level 85) : proto_scope.
Infix "<&{ P2 }>" := (iProto_choice Recv True P2) (at level 85) : proto_scope.
Infix "<{ P1 }+>" := (iProto_choice Send P1 True) (at level 85) : proto_scope.
Infix "<{ P1 }&>" := (iProto_choice Recv P1 True) (at level 85) : proto_scope.
Infix "<+>" := (iProto_choice Send True True) (at level 85) : proto_scope.
Infix "<&>" := (iProto_choice Recv True True) (at level 85) : proto_scope.
  Context `{!heapG Σ, !chanG Σ}.
  Implicit Types p : iProto Σ.
  Implicit Types TT : tele.

  Global Instance iProto_mapsto_ne c : NonExpansive (iProto_mapsto c).
  Proof. rewrite iProto_mapsto_eq. solve_proper. Qed.
  Global Instance iProto_mapsto_proper c : Proper (() ==> ()) (iProto_mapsto c).
  Proof. apply (ne_proper _). Qed.

Robbert Krebbers's avatar
Robbert Krebbers committed
  Lemma iProto_mapsto_le c p1 p2 : c  p1 -∗  (p1  p2) -∗ c  p2.
    rewrite iProto_mapsto_eq. iDestruct 1 as (γ s l r lk ->) "[Hlk H]".
    iIntros "Hle'". iExists γ, s, l, r, lk. iSplit; [done|]. iFrame "Hlk".
    by iApply (iProto_own_le with "H").
Robbert Krebbers's avatar
Robbert Krebbers committed
  Global Instance iProto_choice_contractive n a :
    Proper (dist n ==> dist n ==>
            dist_later n ==> dist_later n ==> dist n) (@iProto_choice Σ a).
  Proof. solve_contractive. Qed.
  Global Instance iProto_choice_ne n a :
    Proper (dist n ==> dist n ==> dist n ==> dist n ==> dist n) (@iProto_choice Σ a).
  Proof. solve_proper. Qed.
  Global Instance iProto_choice_proper a :
    Proper (() ==> () ==> () ==> () ==> ()) (@iProto_choice Σ a).
  Proof. solve_proper. Qed.
Robbert Krebbers's avatar
Robbert Krebbers committed
  Lemma iProto_dual_choice a P1 P2 p1 p2 :
    iProto_dual (iProto_choice a P1 P2 p1 p2)
     iProto_choice (action_dual a) P1 P2 (iProto_dual p1) (iProto_dual p2).
Robbert Krebbers's avatar
Robbert Krebbers committed
    rewrite /iProto_choice iProto_dual_message /= iMsg_dual_exist.
    f_equiv; f_equiv=> -[]; by rewrite iMsg_dual_base.
Robbert Krebbers's avatar
Robbert Krebbers committed
  Lemma iProto_app_choice a P1 P2 p1 p2 q :
    (iProto_choice a P1 P2 p1 p2 <++> q)%proto
     (iProto_choice a P1 P2 (p1 <++> q) (p2 <++> q))%proto.
Robbert Krebbers's avatar
Robbert Krebbers committed
    rewrite /iProto_choice iProto_app_message /= iMsg_app_exist.
    f_equiv; f_equiv=> -[]; by rewrite iMsg_app_base.
Robbert Krebbers's avatar
Robbert Krebbers committed
  Lemma iProto_le_choice a P1 P2 p1 p2 p1' p2' :
    (P1 -∗ P1   (p1  p1'))  (P2 -∗ P2   (p2  p2')) -∗
    iProto_choice a P1 P2 p1 p2  iProto_choice a P1 P2 p1' p2'.
Robbert Krebbers's avatar
Robbert Krebbers committed
    iIntros "H". rewrite /iProto_choice. destruct a;
      iIntros (b) "HP"; iExists b; destruct b;
      iDestruct ("H" with "HP") as "[$ ?]"; by iModIntro.
  (** ** Specifications of [send] and [recv] *)
  Lemma new_chan_spec p :
    {{{ c1 c2, RET (c1,c2); c1  p  c2  iProto_dual p }}}.
  Proof.
    iIntros (Φ _) "HΦ". wp_lam.
    wp_apply (lnil_spec internal_eq with "[//]"); iIntros (l) "Hl".
    wp_apply (lnil_spec internal_eq with "[//]"); iIntros (r) "Hr".
    iMod (iProto_init p) as (γp) "(Hctx & Hcl & Hcr)".
Robbert Krebbers's avatar
Robbert Krebbers committed
    wp_apply (newlock_spec ( vsl vsr,
      llist internal_eq l vsl  llist internal_eq r vsr 
      iProto_ctx γp vsl vsr) with "[Hl Hr Hctx]").
    { iExists [], []. iFrame. }
    iIntros (lk γlk) "#Hlk". wp_pures. iApply "HΦ".
    set (γ := ChanName γlk γp). iSplitL "Hcl".
    - rewrite iProto_mapsto_eq. iExists γ, Left, l, r, lk. by iFrame "Hcl #".
    - rewrite iProto_mapsto_eq. iExists γ, Right, l, r, lk. by iFrame "Hcr #".
  Qed.

  Lemma start_chan_spec p Φ (f : val) :
     ( c, c  iProto_dual p -∗ WP f c {{ _, True }}) -∗
     ( c, c  p -∗ Φ c) -∗
    WP start_chan f {{ Φ }}.
  Proof.
    iIntros "Hfork HΦ". wp_lam.
    wp_apply (new_chan_spec p with "[//]"); iIntros (c1 c2) "[Hc1 Hc2]".
    wp_apply (wp_fork with "[Hfork Hc2]").
    { iNext. wp_apply ("Hfork" with "Hc2"). }
    wp_pures. iApply ("HΦ" with "Hc1").
  Qed.

Robbert Krebbers's avatar
Robbert Krebbers committed
  Lemma send_spec c v p :
    {{{ c  <!> MSG v; p }}}
      send c v
    {{{ RET #(); c  p }}}.
Robbert Krebbers's avatar
Robbert Krebbers committed
    rewrite iProto_mapsto_eq. iIntros (Φ) "Hc HΦ". wp_lam; wp_pures.
    iDestruct "Hc" as (γ s l r lk ->) "[#Hlk H]"; wp_pures.
    wp_apply (acquire_spec with "Hlk"); iIntros "[Hlkd Hinv]".
    iDestruct "Hinv" as (vsl vsr) "(Hl & Hr & Hctx)". destruct s; simpl.
Robbert Krebbers's avatar
Robbert Krebbers committed
    - iMod (iProto_send_l with "Hctx H []") as "[Hctx H]".
      { rewrite iMsg_base_eq /=; auto. }
      wp_apply (lsnoc_spec with "[$Hl //]"); iIntros "Hl".
      wp_apply (llength_spec with "[$Hr //]"); iIntros "Hr".
      wp_apply skipN_spec.
      wp_apply (release_spec with "[Hl Hr Hctx $Hlk $Hlkd]"); [by eauto with iFrame|].
      iIntros "_". iApply "HΦ". iExists γ, Left, l, r, lk. eauto 10 with iFrame.
Robbert Krebbers's avatar
Robbert Krebbers committed
    - iMod (iProto_send_r with "Hctx H []") as "[Hctx H]".
      { rewrite iMsg_base_eq /=; auto. }
      wp_apply (lsnoc_spec with "[$Hr //]"); iIntros "Hr".
      wp_apply (llength_spec with "[$Hl //]"); iIntros "Hl".
      wp_apply skipN_spec.
      wp_apply (release_spec with "[Hl Hr Hctx $Hlk $Hlkd]"); [by eauto with iFrame|].
      iIntros "_". iApply "HΦ". iExists γ, Right, l, r, lk. eauto 10 with iFrame.
  Qed.

Robbert Krebbers's avatar
Robbert Krebbers committed
  Lemma try_recv_spec {TT} c (v : TT  val) (P : TT  iProp Σ) (p : TT  iProto Σ) :
    {{{ c  <?.. x> MSG v x {{  P x }}; p x }}}
Robbert Krebbers's avatar
Robbert Krebbers committed
    {{{ w, RET w; (w = NONEV  c  <?.. x> MSG v x {{  P x }}; p x) 
                  (.. x, w = SOMEV (v x)  c  p x  P x) }}}.
Robbert Krebbers's avatar
Robbert Krebbers committed
    assert ( w lp (m : TT  iMsg Σ),
      iMsg_car (.. x, m x)%msg w lp ⊣⊢ (.. x, iMsg_car (m x) w lp)) as iMsg_texist.
Robbert Krebbers's avatar
Robbert Krebbers committed
    { intros w lp m. clear v P p. rewrite /iMsg_texist iMsg_exist_eq.
      induction TT as [|T TT IH]; simpl; [done|]. f_equiv=> x. apply IH. }
    rewrite iProto_mapsto_eq. iIntros (Φ) "Hc HΦ". wp_lam; wp_pures.
    iDestruct "Hc" as (γ s l r lk ->) "[#Hlk H]"; wp_pures.
    wp_apply (acquire_spec with "Hlk"); iIntros "[Hlkd Hinv]".
    iDestruct "Hinv" as (vsl vsr) "(Hl & Hr & Hctx)". destruct s; simpl.
    - wp_apply (lisnil_spec with "Hr"); iIntros "Hr".
      destruct vsr as [|vr vsr]; wp_pures.
      { wp_apply (release_spec with "[Hl Hr Hctx $Hlk $Hlkd]"); [by eauto with iFrame|].
        iIntros "_". wp_pures. iApply "HΦ". iLeft. iSplit; [done|].
        iExists γ, Left, l, r, lk. eauto 10 with iFrame. }
      wp_apply (lpop_spec with "Hr"); iIntros (v') "[% Hr]"; simplify_eq/=.
      iMod (iProto_recv_l with "Hctx H") as "H". wp_pures.
Robbert Krebbers's avatar
Robbert Krebbers committed
      iMod "H" as (q) "(Hctx & H & Hm)".
      rewrite iMsg_base_eq. iDestruct (iMsg_texist with "Hm") as (x <-) "[Hp HP]".
      wp_apply (release_spec with "[Hl Hr Hctx $Hlk $Hlkd]"); [by eauto with iFrame|].
      iIntros "_". wp_pures. iApply "HΦ". iRight. iExists x. iSplit; [done|].
Robbert Krebbers's avatar
Robbert Krebbers committed
      iFrame "HP". iExists γ, Left, l, r, lk. iSplit; [done|]. iFrame "Hlk".
      by iRewrite "Hp".
    - wp_apply (lisnil_spec with "Hl"); iIntros "Hl".
      destruct vsl as [|vl vsl]; wp_pures.
      { wp_apply (release_spec with "[Hl Hr Hctx $Hlk $Hlkd]"); [by eauto with iFrame|].
        iIntros "_". wp_pures. iApply "HΦ". iLeft. iSplit; [done|].
        iExists γ, Right, l, r, lk. eauto 10 with iFrame. }
      wp_apply (lpop_spec with "Hl"); iIntros (v') "[% Hl]"; simplify_eq/=.
      iMod (iProto_recv_r with "Hctx H") as "H". wp_pures.
Robbert Krebbers's avatar
Robbert Krebbers committed
      iMod "H" as (q) "(Hctx & H & Hm)".
      rewrite iMsg_base_eq. iDestruct (iMsg_texist with "Hm") as (x <-) "[Hp HP]".
      wp_apply (release_spec with "[Hl Hr Hctx $Hlk $Hlkd]"); [by eauto with iFrame|].
      iIntros "_". wp_pures. iApply "HΦ". iRight. iExists x. iSplit; [done|].
Robbert Krebbers's avatar
Robbert Krebbers committed
      iFrame "HP". iExists γ, Right, l, r, lk. iSplit; [done|]. iFrame "Hlk".
      by iRewrite "Hp".
Robbert Krebbers's avatar
Robbert Krebbers committed
  Lemma recv_spec {TT} c (v : TT  val) (P : TT  iProp Σ) (p : TT  iProto Σ) :
    {{{ c  <?.. x> MSG v x {{  P x }}; p x }}}
Robbert Krebbers's avatar
Robbert Krebbers committed
    {{{ x, RET v x; c  p x  P x }}}.
    iIntros (Φ) "Hc HΦ". iLöb as "IH". wp_lam.
Robbert Krebbers's avatar
Robbert Krebbers committed
    wp_apply (try_recv_spec with "Hc"); iIntros (w) "[[-> H]|H]".
    { wp_pures. by iApply ("IH" with "[$]"). }
Robbert Krebbers's avatar
Robbert Krebbers committed
    iDestruct "H" as (x ->) "[Hc HP]". wp_pures. iApply "HΦ". iFrame.
Robbert Krebbers's avatar
Robbert Krebbers committed
  (** ** Specifications for choice *)
  Lemma select_spec c (b : bool) P1 P2 p1 p2 :
    {{{ c  (p1 <{P1}+{P2}> p2)  if b then P1 else P2 }}}
      send c #b
    {{{ RET #(); c  (if b then p1 else p2) }}}.
Robbert Krebbers's avatar
Robbert Krebbers committed
    rewrite /iProto_choice. iIntros (Φ) "[Hc HP] HΦ".
    iApply (send_spec with "[Hc HP] HΦ").
    iApply (iProto_mapsto_le with "Hc").
    iIntros "!>". iExists b. by iFrame "HP".
  Lemma branch_spec c P1 P2 p1 p2 :
    {{{ c  (p1 <{P1}&{P2}> p2) }}}
      recv c
    {{{ b, RET #b; c  (if b : bool then p1 else p2)  if b then P1 else P2 }}}.
Robbert Krebbers's avatar
Robbert Krebbers committed
    rewrite /iProto_choice. iIntros (Φ) "Hc HΦ".
    iApply (recv_spec _ (tele_app _)
      (tele_app (TT:=[tele _ : bool]) (λ b, if b then P1 else P2))%I
      (tele_app _) with "[Hc]").
    { iApply (iProto_mapsto_le with "Hc").
      iIntros "!> /=" (b) "HP". iExists b. by iSplitL. }
    rewrite -bi_tforall_forall.
    iIntros "!>" (x) "[Hc H]". iApply "HΦ". iFrame.
Robbert Krebbers's avatar
Robbert Krebbers committed
End channel.