Newer
Older
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
(** 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.
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 [⊑] *)
From iris.algebra Require Import gmap excl_auth gmap_view.
From iris.heap_lang Require Export primitive_laws notation.
From iris.heap_lang Require Export proofmode.
From iris.heap_lang.lib Require Import spin_lock.
From actris.utils Require Export llist.
From actris.channel Require Import multi_proto_model.
From actris.channel Require Export multi_proto.
Set Default Proof Using "Type".
(* TODO: Update new_chan definition to use pointers with offsets *)
(** * The definition of the message-passing connectives *)
Definition new_chan : val :=
λ: "n",
let: "l" := AllocN ("n"*"n") NONEV in
let: "xxs" := lnil #() in
(rec: "go1" "i" := if: "i" = "n" then #() else
let: "xs" := lnil #() in
(rec: "go2" "j" := if: "j" = "n" then #() else
lcons ("l" +ₗ ("i"*"n"+"j"), "l" +ₗ ("j"*"n"+"i")) "xs";;
"go2" ("j"+#1)) #0;;
lcons "xs" "xxs";;
"go1" ("i"+#1)) #0;; "xxs".
Definition wait : val :=
rec: "go" "c" :=
match: !"c" with
NONE => #()
| SOME <> => "go" "c"
end.
Definition send : val :=
λ: "c" "i" "v",
let: "len" := Fst "c" in
if: "i" < "len" then
let: "l" := Fst (! ((Snd "c") +ₗ "i")) in
"l" <- SOME "v";; wait "l"
(* OBS: Hacky *)
else (rec: "go" <> := "go" #())%V #().
Definition recv : val :=
rec: "go" "c" "i" :=
let: "len" := Fst "c" in
if: "i" < "len" then
let: "l" := Snd (! ((Snd "c") +ₗ "i")) in
let: "v" := Xchg "l" NONEV in
match: "v" with
NONE => "go" "c" "i"
| SOME "v" => "v"
end
(* OBS: Hacky *)
else (rec: "go" <> := "go" #())%V #().
(** * Setup of Iris's cameras *)
Class proto_exclG Σ V :=
protoG_exclG ::
inG Σ (excl_authR (laterO (proto (leibnizO V) (iPropO Σ) (iPropO Σ)))).
Definition proto_exclΣ V := #[
GFunctor (authRF (optionURF (exclRF (laterOF (protoOF (leibnizO V) idOF idOF)))))
].
Class chanG Σ := {
chanG_proto_exclG :: proto_exclG Σ val;
chanG_tokG :: inG Σ (exclR unitO);
chanG_protoG :: protoG Σ val;
}.
Definition chanΣ : gFunctors := #[ proto_exclΣ val; protoΣ val; GFunctor (exclR unitO) ].
Global Instance subG_chanΣ {Σ} : subG chanΣ Σ → chanG Σ.
Proof. solve_inG. Qed.
(** * Definition of the pointsto connective *)
Notation iProto Σ := (iProto Σ val).
Notation iMsg Σ := (iMsg Σ val).
Definition tok `{!chanG Σ} (γ : gname) : iProp Σ := own γ (Excl ()).
Definition chan_inv `{!heapGS Σ, !chanG Σ} γ γE γt i j (l:loc) : iProp Σ :=
(l ↦ NONEV ∗ tok γt) ∨
(∃ v m, l ↦ SOMEV v ∗
iProto_own γ i (<Send j> m)%proto ∗
(∃ p, iMsg_car m v (Next p) ∗ own γE (●E (Next p)))) ∨
(∃ p, l ↦ NONEV ∗
iProto_own γ i p ∗ own γE (●E (Next p))).
Definition iProto_pointsto_def `{!heapGS Σ, !chanG Σ}
(c : val) (i:nat) (p : iProto Σ) : iProp Σ :=
∃ γ γE1 γE2 γt1 γt2 (l:loc) ls,
⌜ c = PairV #(length ls) #l ⌝ ∗
inv (nroot.@"ctx") (iProto_ctx γ) ∗
l ↦∗ ls ∗
([∗list] j ↦ v ∈ ls,
∃ (l1 l2 : loc),
⌜v = PairV #l1 #l2⌝ ∗
inv (nroot.@"p") (chan_inv γ γE1 γt1 i j l1) ∗
inv (nroot.@"p") (chan_inv γ γE2 γt2 j i l2)) ∗
(* llist (λ l v, *)
(* ∃ (j:nat) (l1 l2 : loc), *)
(* ⌜l = (j,(l1,l2))⌝ ∗ ⌜v = PairV #l1 #l2⌝ ∗ *)
(* inv (nroot.@"p") (chan_inv γ γE1 γt1 i j l1) ∗ *)
(* inv (nroot.@"p") (chan_inv γ γE2 γt2 j i l2)) l *)
(* (zip (seq 0 (length ls)) ls) ∗ *)
own γE1 (●E (Next p)) ∗ own γE1 (◯E (Next p)) ∗
iProto_own γ i p.
Definition iProto_pointsto_aux : seal (@iProto_pointsto_def). by eexists. Qed.
Definition iProto_pointsto := iProto_pointsto_aux.(unseal).
Definition iProto_pointsto_eq :
@iProto_pointsto = @iProto_pointsto_def := iProto_pointsto_aux.(seal_eq).
Arguments iProto_pointsto {_ _ _} _ _ _%proto.
Global Instance: Params (@iProto_pointsto) 4 := {}.
Notation "c ↣{ i } p" := (iProto_pointsto c i p)
(at level 20, format "c ↣{ i } p").
Section channel.
Context `{!heapGS Σ, !chanG Σ}.
Implicit Types p : iProto Σ.
Implicit Types TT : tele.
Global Instance iProto_pointsto_ne c i : NonExpansive (iProto_pointsto c i).
Proof. rewrite iProto_pointsto_eq. solve_proper. Qed.
Global Instance iProto_pointsto_proper c i : Proper ((≡) ==> (≡)) (iProto_pointsto c i).
Proof. apply (ne_proper _). Qed.
(* Lemma iProto_pointsto_le c p1 p2 : c ↣ p1 ⊢ ▷ (p1 ⊑ p2) -∗ c ↣ p2. *)
(* Proof. *)
(* rewrite iProto_pointsto_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"). *)
(* Qed. *)
(** ** Specifications of [send] and [recv] *)
Lemma new_chan_spec (n:nat) (ps:gmap nat (iProto Σ)) :
(∀ i, i < n → is_Some (ps !! i)) →
{{{ iProto_consistent ps }}}
new_chan #n
{{{ cs ls, RET #cs;
⌜length ls = n⌝ ∗ cs ↦∗ ls ∗
[∗list] i ↦ l ∈ ls, l ↣{i} (ps !!! i) }}}.
Proof. Admitted.
Lemma own_prot_excl γ i (p1 p2 : iProto Σ) :
own γ (gmap_view_frag i (DfracOwn 1) (Excl' (Next p1))) -∗
own γ (gmap_view_frag i (DfracOwn 1) (Excl' (Next p2))) -∗
False.
Proof. Admitted.
Lemma send_spec c i j v p :
{{{ c ↣{i} <Send j> MSG v; p }}}
send c #j v
{{{ RET #(); c ↣{i} p }}}.
Proof.
rewrite iProto_pointsto_eq. iIntros (Φ) "Hc HΦ". wp_lam; wp_pures.
iDestruct "Hc" as
(γ γE1 γE2 γt1 γt2 l ls ->) "(#IH & Hl & Hls & H● & H◯ & Hown)".
wp_pures.
case_bool_decide; last first.
{ wp_pures. iClear "IH H● H◯ Hown HΦ Hls Hl".
iLöb as "IH". wp_lam. iApply "IH". }
(* assert (is_Some ((zip (seq 0 (length ls)) ls) !! j)) as [l' HSome]. *)
(* { apply lookup_lt_is_Some_2. lia. } *)
(* wp_smart_apply (llookup_spec with "Hls"); [done|]. *)
assert (is_Some (ls !! j)) as [l' HSome].
{ apply lookup_lt_is_Some_2. lia. }
wp_pures.
wp_smart_apply (wp_load_offset with "Hl").
{ done. }
iIntros "Hl". wp_pures.
iDestruct (big_sepL_lookup_acc with "Hls") as "[Hj Hls]"; [done|].
iDestruct "Hj" as (l1 l2 ->) "#[IHl1 IHl2]".
iDestruct ("Hls" with "[]") as "Hls".
{ iExists _, _. iFrame "#". done. }
wp_pures.
wp_bind (Store _ _).
iInv "IHl1" as "HIp".
iDestruct "HIp" as "[HIp|HIp]"; last first.
{ iDestruct "HIp" as "[HIp|HIp]".
- iDestruct "HIp" as (? m) "(>Hl' & Hown' & HIp)".
wp_store.
rewrite /iProto_own.
iDestruct (own_prot_excl with "Hown Hown'") as "H". done.
- iDestruct "HIp" as (p') "(>Hl' & Hown' & HIp)".
wp_store.
rewrite /iProto_own.
iDestruct (own_prot_excl with "Hown Hown'") as "H". done. }
iDestruct "HIp" as "[>Hl' Htok]".
wp_store.
iMod (own_update_2 with "H● H◯") as "[H● H◯]".
{ apply excl_auth_update. }
iModIntro.
iSplitL "Hl' H● Hown".
{ iRight. iLeft. iIntros "!>". iExists _, _. iFrame.
iExists _. iFrame. rewrite iMsg_base_eq. simpl. done. }
wp_pures.
iLöb as "HL".
wp_lam.
wp_bind (Load _).
iInv "IHl1" as "HIp".
iDestruct "HIp" as "[HIp|HIp]".
{ iDestruct "HIp" as ">[Hl' Htok']".
iDestruct (own_valid_2 with "Htok Htok'") as %[]. }
iDestruct "HIp" as "[HIp|HIp]".
- iDestruct "HIp" as (? m) "(>Hl' & Hown & HIp)".
wp_load. iModIntro.
iSplitL "Hl' Hown HIp".
{ iRight. iLeft. iExists _, _. iFrame. }
wp_pures. iApply ("HL" with "HΦ Hl Hls Htok H◯").
- iDestruct "HIp" as (p') "(>Hl' & Hown & H●)".
wp_load.
iModIntro.
iSplitL "Hl' Htok".
{ iLeft. iFrame. }
iDestruct (own_valid_2 with "H● H◯") as "#Hagree".
iDestruct (excl_auth_agreeI with "Hagree") as "Hagree'".
wp_pures.
iMod (own_update_2 with "H● H◯") as "[H● H◯]".
{ apply excl_auth_update. }
iModIntro.
iApply "HΦ".
iExists _, _, _, _, _, _, _.
iSplit; [done|]. iFrame "#∗".
iRewrite -"Hagree'". done.
Qed.
(* Lemma send_spec_tele {TT} c (tt : TT) *)
(* (v : TT → val) (P : TT → iProp Σ) (p : TT → iProto Σ) : *)
(* {{{ c ↣ (<!.. x > MSG v x {{ P x }}; p x) ∗ P tt }}} *)
(* send c (v tt) *)
(* {{{ RET #(); c ↣ (p tt) }}}. *)
(* Proof. *)
(* iIntros (Φ) "[Hc HP] HΦ". *)
(* iDestruct (iProto_pointsto_le _ _ (<!> MSG v tt; p tt)%proto with "Hc [HP]") *)
(* as "Hc". *)
(* { iIntros "!>". *)
(* iApply iProto_le_trans. *)
(* iApply iProto_le_texist_intro_l. *)
(* by iFrame "HP". } *)
(* by iApply (send_spec with "Hc"). *)
(* Qed. *)
Lemma recv_spec {TT} c i j (v : TT → val) (P : TT → iProp Σ) (p : TT → iProto Σ) :
{{{ c ↣{i} <(Recv j) @.. x> MSG v x {{ ▷ P x }}; p x }}}
recv c #j
{{{ x, RET v x; c ↣{i} p x ∗ P x }}}.
Proof.
iIntros (Φ) "Hc HΦ". iLöb as "HL". wp_lam.
rewrite iProto_pointsto_eq.
iDestruct "Hc" as
(γ γE1 γE2 γt1 γt2 l ls ->) "(#IH & Hl & Hls & H● & H◯ & Hown)".
wp_pures.
case_bool_decide; last first.
{ wp_pures. iClear "IH H● H◯ Hown HΦ Hls Hl".
iLöb as "IH". wp_lam. iApply "IH". }
wp_pures.
assert (is_Some (ls !! j)) as [l' HSome].
{ apply lookup_lt_is_Some_2. lia. }
wp_smart_apply (wp_load_offset with "Hl").
{ done. }
iIntros "Hl". wp_pures.
iDestruct (big_sepL_lookup_acc with "Hls") as "[Hj Hls]"; [done|].
iDestruct "Hj" as (l1 l2 ->) "#[IHl1 IHl2]".
iDestruct ("Hls" with "[]") as "Hls".
{ iExists _, _. iFrame "#". done. }
wp_pures.
wp_bind (Xchg _ _).
iInv "IHl2" as "HIp".
iDestruct "HIp" as "[HIp|HIp]".
{ iDestruct "HIp" as ">[Hl' Htok]".
wp_xchg.
iModIntro.
iSplitL "Hl' Htok".
{ iLeft. iFrame. }
wp_pures. iApply ("HL" with "[H● H◯ Hown Hls Hl] HΦ").
iExists _, _, _, _, _, _, _. iSplit; [done|]. iFrame "#∗". }
iDestruct "HIp" as "[HIp|HIp]"; last first.
{ iDestruct "HIp" as (p') "[>Hl' [Hown' H◯']]".
wp_xchg.
iModIntro.
iSplitL "Hl' Hown' H◯'".
{ iRight. iRight. iExists _. iFrame. }
wp_pures. iApply ("HL" with "[H● H◯ Hown Hls Hl] HΦ").
iExists _, _, _, _, _, _, _. iSplit; [done|]. iFrame "#∗". }
iDestruct "HIp" as (w m) "(>Hl' & Hown' & HIp)".
iDestruct "HIp" as (p') "[Hm Hp']".
iInv "IH" as "Hctx".
wp_xchg.
iMod (iProto_step with "Hctx Hown' Hown Hm") as
(p'') "(Hm & Hctx & Hown & Hown')".
iModIntro.
iSplitL "Hctx"; [done|].
iModIntro.
iSplitL "Hl' Hown Hp'".
{ iRight. iRight. iExists _. iFrame. }
wp_pure _.
rewrite iMsg_base_eq.
iDestruct (iMsg_texist_exist with "Hm") as (x <-) "[Hp HP]".
wp_pures.
iMod (own_update_2 with "H● H◯") as "[H● H◯]".
{ apply excl_auth_update. }
iModIntro. iApply "HΦ".
iFrame.
iExists _, _, _, _, _, _, _. iSplit; [done|].
iRewrite "Hp". iFrame "#∗".
Qed.
End channel.