bedrock.lang.bi.spec.contender_token
(*
* Copyright (C) BedRock Systems Inc. 2020-2022
*
* This software is distributed under the terms of the BedRock Open-Source License.
* See the LICENSE-BedRock file in the repository root for details.
*)
Require Import bedrock.lang.bi.prelude.
Require Import bedrock.lang.bi.big_op.
Require Import bedrock.lang.proofmode.proofmode.
Import ChargeNotation.
#[local] Set Primitive Projections.
#[local] Open Scope N_scope.
* Copyright (C) BedRock Systems Inc. 2020-2022
*
* This software is distributed under the terms of the BedRock Open-Source License.
* See the LICENSE-BedRock file in the repository root for details.
*)
Require Import bedrock.lang.bi.prelude.
Require Import bedrock.lang.bi.big_op.
Require Import bedrock.lang.proofmode.proofmode.
Import ChargeNotation.
#[local] Set Primitive Projections.
#[local] Open Scope N_scope.
Spec building block: Contender tokens
Class ContenderToken {PROP : bi} (P : N → PROP) : Prop := {
#[global] contender_timeless n :: Timeless (P n);
#[global] contender_affine n :: Affine (P n);
#[global] contender_timeless n :: Timeless (P n);
#[global] contender_affine n :: Affine (P n);
contender_op or the derived rule contender_alloc are used to
split off individual contender tokens.
Example:_ Suppose there are 8 cores and ticket lock tickets occupy
16 bits. When an initializing core A allocates a lock, it gets a
bunch of contender tokens, written contender γ (2 ^ 16 - 1). When
A informs some other core B about this lock, A has n ≠ 0 tokens
left and peels off a single token using contender_alloc. A passes
contender γ 1 to B and keeps the remaining n - 1 tokens. After
doling out a token per core in this way, A can discard the remaining
2 ^ 16 - 9 tokens.
contender_op n1 n2 : P (n1 + n2) -|- P n1 ** P n2;
}.
Section with_contender.
Context {PROP : bi} {P : N -> PROP} `{CT : !ContenderToken P}.
#[local] Set Default Proof Using "CT".
Lemma contender_alloc (n : N) :
n ≠ 0 → P n -|- P (N.pred n) ** P 1.
Proof.
intros. have {1}-> : (n = N.pred n + 1)%N by lia. exact: contender_op.
Qed.
Lemma contender_allocN (tk c : N) :
(tk <= c)%N ->
P c -|- P (c - tk) ** P tk.
Proof.
intros. have {1}->: (c = (c - tk) + tk)%N by lia. exact: contender_op.
Qed.
Lemma contender_split (n : N) :
P n -|- P 0 ** P 1 ^^ n.
Proof.
induction n as [|n IH] using N.peano_ind.
- by rewrite power_0 right_id.
- by rewrite -N.add_1_r contender_op power_add power_1 IH assoc.
Qed.
Lemma contender_split_leaking_0 (n : N) :
P n |-- P 1 ^^ n.
Proof. rewrite contender_split. iIntros "[? $]". Qed.
}.
Section with_contender.
Context {PROP : bi} {P : N -> PROP} `{CT : !ContenderToken P}.
#[local] Set Default Proof Using "CT".
Lemma contender_alloc (n : N) :
n ≠ 0 → P n -|- P (N.pred n) ** P 1.
Proof.
intros. have {1}-> : (n = N.pred n + 1)%N by lia. exact: contender_op.
Qed.
Lemma contender_allocN (tk c : N) :
(tk <= c)%N ->
P c -|- P (c - tk) ** P tk.
Proof.
intros. have {1}->: (c = (c - tk) + tk)%N by lia. exact: contender_op.
Qed.
Lemma contender_split (n : N) :
P n -|- P 0 ** P 1 ^^ n.
Proof.
induction n as [|n IH] using N.peano_ind.
- by rewrite power_0 right_id.
- by rewrite -N.add_1_r contender_op power_add power_1 IH assoc.
Qed.
Lemma contender_split_leaking_0 (n : N) :
P n |-- P 1 ^^ n.
Proof. rewrite contender_split. iIntros "[? $]". Qed.
Proof mode
#[global] Instance contender_into_sep n1 n2 :
IntoSep (P (n1 + n2)) (P n1) (P n2).
Proof. by rewrite /IntoSep contender_op. Qed.
#[global] Instance contender_from_sep n1 n2 :
FromSep (P (n1 + n2)) (P n1) (P n2).
Proof. by rewrite /FromSep contender_op. Qed.
#[global] Instance contender_combine_sep_as n1 n2 :
CombineSepAs (P n1) (P n2) (P (n1 + n2)).
Proof. by rewrite /CombineSepAs contender_op. Qed.
End with_contender.
#[global] Instance ContenderToken_sep {PROP : bi} (P Q : N -> PROP) :
ContenderToken P -> ContenderToken Q ->
ContenderToken (funI n => P n ** Q n).
Proof.
constructor; [apply _..|].
intros n1 n2. trans ((P n1 ** P n2) ** (Q n1 ** Q n2)).
- by rewrite !contender_op.
- rewrite !bi.sep_assoc. rewrite -(bi.sep_assoc (P n1) (P n2) (Q n1)).
rewrite (bi.sep_comm (P n2) (Q n1)). by rewrite bi.sep_assoc.
Qed.
IntoSep (P (n1 + n2)) (P n1) (P n2).
Proof. by rewrite /IntoSep contender_op. Qed.
#[global] Instance contender_from_sep n1 n2 :
FromSep (P (n1 + n2)) (P n1) (P n2).
Proof. by rewrite /FromSep contender_op. Qed.
#[global] Instance contender_combine_sep_as n1 n2 :
CombineSepAs (P n1) (P n2) (P (n1 + n2)).
Proof. by rewrite /CombineSepAs contender_op. Qed.
End with_contender.
#[global] Instance ContenderToken_sep {PROP : bi} (P Q : N -> PROP) :
ContenderToken P -> ContenderToken Q ->
ContenderToken (funI n => P n ** Q n).
Proof.
constructor; [apply _..|].
intros n1 n2. trans ((P n1 ** P n2) ** (Q n1 ** Q n2)).
- by rewrite !contender_op.
- rewrite !bi.sep_assoc. rewrite -(bi.sep_assoc (P n1) (P n2) (Q n1)).
rewrite (bi.sep_comm (P n2) (Q n1)). by rewrite bi.sep_assoc.
Qed.