Skip to content
Snippets Groups Projects
Commit fed91e19 authored by Hai Dang's avatar Hai Dang
Browse files

complete spawn/join

parent 9a6443c9
No related branches found
No related tags found
No related merge requests found
Pipeline #
...@@ -51,6 +51,8 @@ theories/typing/lib/option.v ...@@ -51,6 +51,8 @@ theories/typing/lib/option.v
theories/typing/lib/panic.v theories/typing/lib/panic.v
theories/typing/lib/swap.v theories/typing/lib/swap.v
theories/typing/lib/take_mut.v theories/typing/lib/take_mut.v
theories/typing/lib/spawn.v
theories/typing/lib/join.v
theories/typing/lib/rc/rc.v theories/typing/lib/rc/rc.v
theories/typing/lib/rc/weak.v theories/typing/lib/rc/weak.v
theories/typing/lib/mutex/mutex.v theories/typing/lib/mutex/mutex.v
......
...@@ -4,8 +4,6 @@ From iris.algebra Require Import excl. ...@@ -4,8 +4,6 @@ From iris.algebra Require Import excl.
From lrust.lang Require Import notation. From lrust.lang Require Import notation.
From gpfsl.gps Require Import middleware protocols escrows. From gpfsl.gps Require Import middleware protocols escrows.
From iris.bi Require Import bi.
Lemma monPred_in_elim_vProp `{Σ: gFunctors} (P : vProp Σ) (V : view): Lemma monPred_in_elim_vProp `{Σ: gFunctors} (P : vProp Σ) (V : view):
(monPred_in V P) -∗ V', P V' ⎤. (monPred_in V P) -∗ V', P V' ⎤.
Proof. Proof.
......
From iris.proofmode Require Import tactics.
From iris.bi Require Import big_op.
From lrust.lang Require Import spawn.
From lrust.typing Require Export type.
From lrust.typing Require Import typing.
Set Default Proof Using "Type".
Definition joinN := lrustN .@ "join".
Section join.
Context `{!typeG Σ, !spawnG Σ}.
(* This model is very far from rayon::join, which uses a persistent
work-stealing thread-pool. Still, the important bits are right:
One of the closures is executed in another thread, and the
closures can refer to on-stack data (no 'static' bound). *)
Definition join (call_once_A call_once_B : val) (R_A R_B : type) : val :=
funrec: <> ["fA"; "fB"] :=
let: "call_once_A" := call_once_A in
let: "call_once_B" := call_once_B in
let: "join" := spawn [λ: ["c"],
letcall: "r" := "call_once_A" ["fA"]%E in
finish ["c"; "r"]] in
letcall: "retB" := "call_once_B" ["fB"]%E in
let: "retA" := join ["join"] in
(* Put the results in a pair. *)
let: "ret" := new [ #(R_A.(ty_size) + R_B.(ty_size)) ] in
"ret" + #0 <-{R_A.(ty_size)} !"retA";;
"ret" + #R_A.(ty_size) <-{R_B.(ty_size)} !"retB";;
delete [ #R_A.(ty_size); "retA"] ;; delete [ #R_B.(ty_size); "retB"] ;;
return: ["ret"].
Lemma join_type A B R_A R_B call_once_A call_once_B
`{!TyWf A, !TyWf B, !TyWf R_A, !TyWf R_B}
`(!Send A, !Send B, !Send R_A, !Send R_B) :
(* A : FnOnce() -> R_A, as witnessed by the impl call_once_A *)
typed_val call_once_A (fn(; A) R_A)
(* B : FnOnce() -> R_B, as witnessed by the impl call_once_B *)
typed_val call_once_B (fn(; B) R_B)
typed_val (join call_once_A call_once_B R_A R_B) (fn(; A, B) Π[R_A; R_B]).
Proof using Type*.
intros HfA HfB E L. iApply type_fn; [solve_typing..|]. iIntros "/= !#".
iIntros (_ ϝ ret arg). inv_vec arg=>envA envB. simpl_subst.
iApply type_let; [apply HfA|solve_typing|]. iIntros (fA); simpl_subst.
iApply type_let; [apply HfB|solve_typing|]. iIntros (fB); simpl_subst.
(* Drop to Iris. *)
iIntros (tid) "#LFT #HE Hna HL Hk (HfB & HfA & HenvA & HenvB & _)".
iMod (lctx_lft_alive_tok ϝ with "HE HL") as (qϝ1) "(Hϝ1 & HL & Hclose1)";
[solve_typing..|].
(* FIXME: using wp_apply here breaks calling solve_to_val. *)
wp_bind (spawn _).
iApply ((spawn_spec joinN (λ v, (box R_A).(ty_own) tid [v] (qϝ1).[ϝ])%I) with "[HfA HenvA Hϝ1]");
first solve_to_val; first simpl_subst.
{ (* The new thread. *)
iIntros (γc γe c tid') "Hfin". iMod na_alloc as (tid2) "Htl". wp_let. wp_let. unlock.
rewrite !tctx_hasty_val.
iApply (type_call_iris _ [ϝ] () [_] _ (Build_thread_id tid2 tid') with "LFT HE Htl [Hϝ1] HfA [HenvA]").
- rewrite outlives_product. solve_typing.
- by rewrite /= (right_id static).
- by rewrite bi.big_sepL_singleton tctx_hasty_val send_change_tid.
- iIntros (r) "Htl Hϝ1 Hret".
wp_rec. iApply (finish_spec with "[$Hfin Hret Hϝ1]"); [solve_ndisj..| |auto].
rewrite right_id. iFrame. by iApply @send_change_tid. }
iNext. iIntros (γc γe c) "Hjoin". wp_let. wp_let.
iMod (lctx_lft_alive_tok ϝ with "HE HL") as (qϝ2) "(Hϝ2 & HL & Hclose2)";
[solve_typing..|].
rewrite !tctx_hasty_val.
iApply (type_call_iris _ [ϝ] () [_] with "LFT HE Hna [Hϝ2] HfB [HenvB]").
{ rewrite outlives_product. solve_typing. }
{ by rewrite /= (right_id static). }
{ by rewrite bi.big_sepL_singleton tctx_hasty_val. }
(* The return continuation after calling fB in the main thread. *)
iIntros (retB) "Hna Hϝ2 HretB". rewrite /= (right_id static).
iMod ("Hclose2" with "Hϝ2 HL") as "HL". wp_rec.
wp_apply (join_spec with "Hjoin"); [solve_ndisj..|]. iIntros (retA) "[HretA Hϝ1]".
iMod ("Hclose1" with "Hϝ1 HL") as "HL". wp_let.
(* Switch back to type system mode. *)
iApply (type_type _ _ _ [ retA box R_A; retB box R_B ]
with "[] LFT HE Hna HL Hk [-]"); last first.
{ rewrite tctx_interp_cons tctx_interp_singleton !tctx_hasty_val. iFrame. }
iApply (type_new_subtype (Π[uninit R_A.(ty_size); uninit R_B.(ty_size)]));
(* FIXME: solve_typing should handle this without any aid. *)
rewrite ?Z_nat_add; [solve_typing..|].
iIntros (r); simpl_subst.
iApply (type_memcpy R_A); [solve_typing..|].
iApply (type_memcpy R_B); [solve_typing..|].
iApply type_delete; [solve_typing..|].
iApply type_delete; [solve_typing..|].
iApply type_jump; solve_typing.
Qed.
End join.
From iris.proofmode Require Import tactics.
From iris.bi Require Import big_op.
From lrust.lang Require Import spawn.
From lrust.typing Require Export type.
From lrust.typing Require Import typing.
Set Default Proof Using "Type".
Definition spawnN := lrustN .@ "spawn".
Section join_handle.
Context `{!typeG Σ, !spawnG Σ}.
Definition join_inv tid (ty : type) (v : val) :=
(box ty).(ty_own) tid [v].
Program Definition join_handle (ty : type) :=
{| ty_size := 1;
ty_own tid vl :=
match vl return _ with
| [ #(LitLoc l) ] => γc γe, join_handle spawnN γc γe l (join_inv tid ty)
| _ => False
end%I;
ty_shr κ tid l := True%I |}.
Next Obligation. by iIntros (ty tid [|[[]|][]]) "H". Qed.
Next Obligation. iIntros "* _ _ _ $". auto. Qed.
Next Obligation. iIntros (?) "**"; auto. Qed.
Global Instance join_handle_wf ty `{!TyWf ty} : TyWf (join_handle ty) :=
{ ty_lfts := ty.(ty_lfts); ty_wf_E := ty.(ty_wf_E) }.
Lemma join_handle_subtype ty1 ty2 :
type_incl ty1 ty2 -∗ type_incl (join_handle ty1) (join_handle ty2).
Proof.
iIntros "#Hincl". iSplit; first done. iSplit; iAlways.
- iIntros "* Hvl". destruct vl as [|[[|vl|]|] [|]]; try done.
simpl. iDestruct "Hvl" as (γc γe) "Hvl". iExists γc, γe.
iApply (join_handle_impl with "[] Hvl"). iIntros "!# * Hown".
iDestruct (box_type_incl with "Hincl") as "{Hincl} (_ & Hincl & _)".
iApply "Hincl". done.
- iIntros "* _". auto.
Qed.
Global Instance join_handle_mono E L :
Proper (subtype E L ==> subtype E L) join_handle.
Proof.
iIntros (ty1 ty2 Hsub ?) "HL". iDestruct (Hsub with "HL") as "#Hsub".
iIntros "!# #HE". iApply join_handle_subtype. iApply "Hsub"; done.
Qed.
Global Instance join_handle_proper E L :
Proper (eqtype E L ==> eqtype E L) join_handle.
Proof. intros ??[]. by split; apply join_handle_mono. Qed.
Global Instance join_handle_type_contractive : TypeContractive join_handle.
Proof.
constructor;
solve_proper_core ltac:(fun _ => exact: type_dist2_dist || f_type_equiv || f_contractive || f_equiv).
Qed.
Global Instance join_handle_ne : NonExpansive join_handle.
Proof. apply type_contractive_ne, _. Qed.
Global Instance join_handle_send ty :
Send ty Send (join_handle ty).
Proof.
iIntros (??? vl) "Hvl". destruct vl as [|[[|vl|]|] [|]]; try done.
simpl. iDestruct "Hvl" as (γc γe) "Hvl". iExists γc, γe.
iApply (join_handle_impl with "[] Hvl"). iIntros "!# * Hv".
unfold join_inv. iApply @send_change_tid. done.
Qed.
Global Instance join_handle_sync ty : Sync (join_handle ty).
Proof. iIntros (????) "_ //". Qed.
End join_handle.
Section spawn.
Context `{!typeG Σ, !spawnG Σ}.
Definition spawn (call_once : val) : val :=
funrec: <> ["f"] :=
let: "call_once" := call_once in
let: "join" := spawn [λ: ["c"],
letcall: "r" := "call_once" ["f":expr] in
finish ["c"; "r"]] in
letalloc: "r" <- "join" in
return: ["r"].
Lemma spawn_type fty retty call_once `{!TyWf fty, !TyWf retty}
`(!Send fty, !Send retty) :
typed_val call_once (fn(; fty) retty) (* fty : FnOnce() -> retty, as witnessed by the impl call_once *)
let E ϝ := fty.(ty_outlives_E) static ++ retty.(ty_outlives_E) static in
typed_val (spawn call_once) (fn(E; fty) join_handle retty).
Proof.
intros Hf ? E L. iApply type_fn; [solve_typing..|]. iIntros "/= !#".
iIntros (_ ϝ ret arg). inv_vec arg=>env. simpl_subst.
iApply type_let; [apply Hf|solve_typing|]. iIntros (f'). simpl_subst.
iApply (type_let _ _ _ _ ([f' _; env _])
(λ j, [j join_handle retty])); try solve_typing; [|].
{ (* The core of the proof: showing that spawn is safe. *)
iIntros (tid) "#LFT #HE $ $ [Hf' [Henv _]]". rewrite !tctx_hasty_val [fn _]lock.
iApply (spawn_spec _ (join_inv tid retty) with "[-]");
first solve_to_val; last first; last simpl_subst.
{ iIntros "!> *". rewrite tctx_interp_singleton tctx_hasty_val.
iIntros "?". iExists _,_. by iFrame. }
iIntros (γc γe c tid') "Hfin". iMod na_alloc as (tid2) "Htl". wp_let. wp_let. unlock.
iApply (type_call_iris _ [] () [_] _ (Build_thread_id tid2 tid') with "LFT HE Htl [] Hf' [Henv]");
(* The `solve_typing` here shows that, because we assume that `fty` and `retty`
outlive `static`, the implicit requirmeents made by `call_once` are satisifed. *)
[solve_typing|iApply (lft_tok_static 1%Qp)| |].
- by rewrite bi.big_sepL_singleton tctx_hasty_val send_change_tid.
- iIntros (r) "Htl _ Hret".
wp_rec. iApply (finish_spec with "[$Hfin Hret]"); [solve_ndisj..| |auto].
by iApply @send_change_tid. }
iIntros (v). simpl_subst.
iApply type_new; [solve_typing..|]. iIntros (r). simpl_subst.
iApply type_assign; [solve_typing..|].
iApply type_jump; solve_typing.
Qed.
Definition join : val :=
funrec: <> ["c"] :=
let: "c'" := !"c" in
let: "r" := join ["c'"] in
delete [ #1; "c"];; return: ["r"].
Lemma join_type retty `{!TyWf retty} :
typed_val join (fn(; join_handle retty) retty).
Proof.
intros E L. iApply type_fn; [solve_typing..|]. iIntros "/= !#".
iIntros (_ ϝ ret arg). inv_vec arg=>c. simpl_subst.
iApply type_deref; [solve_typing..|]. iIntros (c'); simpl_subst.
iApply (type_let _ _ _ _ ([c' _])
(λ r, [r box retty])); try solve_typing; [|].
{ iIntros (tid) "#LFT _ $ $".
rewrite tctx_interp_singleton tctx_hasty_val. iIntros "Hc".
destruct c' as [[|c'|]|]; try done. iDestruct "Hc" as (??) "Hc".
iApply (join_spec with "Hc"); [solve_ndisj..|]. iNext. iIntros "* Hret".
rewrite tctx_interp_singleton tctx_hasty_val. done. }
iIntros (r); simpl_subst. iApply type_delete; [solve_typing..|].
iApply type_jump; solve_typing.
Qed.
End spawn.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment