Commit 815b0180 authored by Ralf Jung's avatar Ralf Jung

Merge branch 'rdcss_comment' into 'master'

Comment in the RDCSS spec about GClocs.

See merge request iris/examples!29
parents 8de152b1 6639940c
...@@ -7,64 +7,97 @@ From iris_examples.logatom.rdcss Require Import spec. ...@@ -7,64 +7,97 @@ From iris_examples.logatom.rdcss Require Import spec.
Import uPred bi List Decidable. Import uPred bi List Decidable.
Set Default Proof Using "Type". Set Default Proof Using "Type".
(** Using prophecy variables with helping: implementing a simplified version of (** We consider here an implementation of the RDCSS (Restricted Double-Compare
the restricted double-compare single-swap from "A Practical Multi-Word Compare-and-Swap Operation" by Harris et al. (DISC 2002) Single-Swap) data structure of Harris et al., as described in "A Practical
*) Multi-Word Compare-and-Swap Operation" (DISC 2002).
(** * Implementation of the functions. *) Our goal is to prove logical atomicity for the operations of RDCSS, and to
do so we will need to use prophecy variables! This Coq file is part of the
(* 1) The M location l_m can differ when helping another thread in the same RDCSS instance artifact accompanying the paper "The Future is Ours: Prophecy Variables in
(Harris et al. refer to it as a location in the control section.) Separation Logic" (POPL 2020). Proving logical atomicity for RDCSS appears
2) The N location l_n identifies a single RDCSS instance. as a major case study in the paper, so it makes sense to read the relevant
(Harris et al. refer to it as a location in the data section.) sections first (§4 to §6) to better understand the Coq proof. The paper is
3) There are two kinds of values stored at N locations available online at: <https://plv.mpi-sws.org/prophecies/>. *)
3.1) The value is injL n for some n: no operation is on-going and the logical state is n. (** * Implementation of the RDCSS operations *)
3.2) The value is injR l_descr for some location l_descr (which we call a descriptor):
l_descr must point to a tuple (l_m, m1, n1, n2, p) for some M location l_m, values m1, n1, n2 and prophecy p. (** The RDCSS data structure manipulates two kinds of locations:
In this case an operation is on-going with corresponding M location l_m. - N-locations (a.k.a. RDCSS locations) denoted [l_n] identify a particular
*) instance of RDCSS. (Harris et al. refer to them as locations in the data
section.) They are the locations that may be updated by a call to RDCSS.
(* - M-locations denoted [l_m] are not tied to a particular RDCSS instance.
(Harris et al. refer to them as locations in the control section.) They
are never directly modified by the RDCSS operation, but they are subject
to arbitrary interference by other heap operations.
An N-location can contain values of two forms.
- A value of the form [injL n] indicates that there is currently no active
RDCSS operation on the N-location, and that the location has the logical
value [n]. In that case, the N-location is in a "quiescent" state.
- A value of the form [injR descr] indicates that the RDCSS operation that
is identified by descriptor [descr] is ongoing. In that case, descriptor
[descr] must point to a tuple [(l_m, m1, n1, n2, p)] for some M-location
[l_m], integers [m1], [n1], [n2] and prophecy [p]. An N-location holding
a value of the form [injR descr] is in an "updating" state. *)
(** As mentioned in the paper, there are minor differences between our version
of RDCSS and the original one (by Harris et al.):
- In the original version, the RDCSS operation takes as input a descriptor
for the operation, whereas in our version the RDCSS operation allocates
the descriptor itself.
- In the original version, values (inactive state) and descriptors (active
state) are distinguished by looking at their least significant bits. Our
version rather relies on injections to avoid bit-level manipulations. *)
(** The [new_rdcss] operation creates a new RDCSS location. It corresponds to
the following pseudo-code:
<<
new_rdcss(n) := ref (injL n) new_rdcss(n) := ref (injL n)
*) >>
*)
Definition new_rdcss : val := λ: "n", ref (InjL "n"). Definition new_rdcss : val := λ: "n", ref (InjL "n").
(* (** The [complete] function is used internally by the RDCSS operations. It can
be expressed using the following pseudo-code:
<<
complete(l_descr, l_n) := complete(l_descr, l_n) :=
let (l_m, m1, n1, n2, p) := !l_descr in let (l_m, m1, n1, n2, p) := !l_descr;
(* data = (l_m, m1, n1, n2, p) *) (* data = (l_m, m1, n1, n2, p) *)
let tid_ghost = NewProph in let tid_ghost = NewProph;
let n_new = (if !l_m = m1 then n1 else n2) in let n_new = (if !l_m = m1 then n1 else n2);
Resolve (CmpXchg l_n (InjR l_descr) (ref (InjL n_new))) p tid_ghost ; #(). Resolve (CmpXchg l_n (InjR l_descr) (ref (InjL n_new))) p tid_ghost;
*) #().
>>
In this function, we rely on a prophecy variable to emulate a ghost thread
identifier. In particular, the corresponding prophecy variable [tid_ghost]
is never resolved. Here, the main reason for using a prophecy variable is
that we can use erasure to argue that it has no effect on the code. *)
Definition complete : val := Definition complete : val :=
λ: "l_descr" "l_n", λ: "l_descr" "l_n",
let: "data" := !"l_descr" in let: "data" := !"l_descr" in (* data = (l_m, m1, n1, n2, p) *)
(* data = (l_m, m1, n1, n2, p) *)
let: "l_m" := Fst (Fst (Fst (Fst ("data")))) in let: "l_m" := Fst (Fst (Fst (Fst ("data")))) in
let: "m1" := Snd (Fst (Fst (Fst ("data")))) in let: "m1" := Snd (Fst (Fst (Fst ("data")))) in
let: "n1" := Snd (Fst (Fst ("data"))) in let: "n1" := Snd (Fst (Fst ("data"))) in
let: "n2" := Snd (Fst ("data")) in let: "n2" := Snd (Fst ("data")) in
let: "p" := Snd ("data") in let: "p" := Snd ("data") in
(* Create a thread identifier using NewProph. (* Create a thread identifier using NewProph. *)
tid_ghost is not used as a traditional prophecy, i.e. it is never resolved.
The reason we use NewProph is so that we can use the erasure theorem to argue that
it has no effect on the code.
*)
let: "tid_ghost" := NewProph in let: "tid_ghost" := NewProph in
let: "n_new" := (if: !"l_m" = "m1" then "n2" else "n1") in let: "n_new" := (if: !"l_m" = "m1" then "n2" else "n1") in
Resolve (CmpXchg "l_n" (InjR "l_descr") (InjL "n_new")) "p" "tid_ghost" ;; #(). Resolve (CmpXchg "l_n" (InjR "l_descr") (InjL "n_new")) "p" "tid_ghost";;
#().
(*
get(l_n) := (** The [get] operation reads the value stored in an RDCSS location previously
match: !l_n with created using [new_rdcss]. In pseudo-code, it corresponds to:
| injL n => n <<
| injR (l_descr) => rec get(l_n) :=
complete(l_descr, l_n); match !l_n with
get(l_n) | injL n => n
end. | injR l_descr => complete(l_descr, l_n);
*) get(l_n)
end
>>
*)
Definition get : val := Definition get : val :=
rec: "get" "l_n" := rec: "get" "l_n" :=
match: !"l_n" with match: !"l_n" with
...@@ -74,30 +107,32 @@ Definition get : val := ...@@ -74,30 +107,32 @@ Definition get : val :=
"get" "l_n" "get" "l_n"
end. end.
(* (** Finally, the [rdcss] operation corresponds to the following pseudo-code:
<<
rdcss(l_m, l_n, m1, n1, n2) := rdcss(l_m, l_n, m1, n1, n2) :=
let p := NewProph in let p := NewProph;
let l_descr := ref (l_m, m1, n1, n2, p) in let l_descr := ref (l_m, m1, n1, n2, p);
(rec: rdcss_inner() rec rdcss_inner() =
let (r, b) := CmpXchg(l_n, InjL n1, InjR l_descr) in let (r, b) := CmpXchg(l_n, InjL n1, InjR l_descr) in
match r with match r with
InjL n => | InjL n =>
if b then if b then
complete(l_descr, l_n) ; n1 complete(l_descr, l_n); n1
else else
n n
| InjR l_descr_other => | InjR l_descr_other =>
complete(l_descr_other, l_n) ; complete(l_descr_other, l_n);
rdcss_inner() rdcss_inner()
end end;
)() rdcss_inner()
>>
*) *)
Definition rdcss: val := Definition rdcss: val :=
λ: "l_m" "l_n" "m1" "n1" "n2", λ: "l_m" "l_n" "m1" "n1" "n2",
(* allocate fresh descriptor *) (* Allocate the descriptor for the operation. *)
let: "p" := NewProph in let: "p" := NewProph in
let: "l_descr" := ref ("l_m", "m1", "n1", "n2", "p") in let: "l_descr" := ref ("l_m", "m1", "n1", "n2", "p") in
(* start rdcss computation with allocated descriptor *) (* Attempt to establish the descriptor to make the operation "active". *)
( rec: "rdcss_inner" "_" := ( rec: "rdcss_inner" "_" :=
let: "r" := CmpXchg "l_n" (InjL "n1") (InjR "l_descr") in let: "r" := CmpXchg "l_n" (InjL "n1") (InjR "l_descr") in
match: Fst "r" with match: Fst "r" with
...@@ -110,8 +145,9 @@ Definition rdcss: val := ...@@ -110,8 +145,9 @@ Definition rdcss: val :=
(* CmpXchg failed, hence we could linearize at the CmpXchg *) (* CmpXchg failed, hence we could linearize at the CmpXchg *)
"n" "n"
| InjR "l_descr_other" => | InjR "l_descr_other" =>
(* a descriptor from a different operation was read, try to help and then restart *) (* A descriptor from a concurrent operation was read, try to help
complete "l_descr_other" "l_n" ;; and then restart. *)
complete "l_descr_other" "l_n";;
"rdcss_inner" #() "rdcss_inner" #()
end end
) #(). ) #().
...@@ -138,7 +174,7 @@ Section rdcss. ...@@ -138,7 +174,7 @@ Section rdcss.
Context {Σ} `{!heapG Σ, !rdcssG Σ, !gcG Σ }. Context {Σ} `{!heapG Σ, !rdcssG Σ, !gcG Σ }.
Context (N : namespace). Context (N : namespace).
Local Definition descrN := N .@ "descr". Local Definition descrN := N .@ "descr".
Local Definition rdcssN := N .@ "rdcss". Local Definition rdcssN := N .@ "rdcss".
(** Updating and synchronizing the value RAs *) (** Updating and synchronizing the value RAs *)
...@@ -165,12 +201,12 @@ Section rdcss. ...@@ -165,12 +201,12 @@ Section rdcss.
Fixpoint proph_extract_winner (pvs : list (val * val)) : option proph_id := Fixpoint proph_extract_winner (pvs : list (val * val)) : option proph_id :=
match pvs with match pvs with
| (_, LitV (LitProphecy tid)) :: _ => Some tid | (_, LitV (LitProphecy tid)) :: _ => Some tid
| _ => None | _ => None
end. end.
Inductive abstract_state : Set := Inductive abstract_state : Set :=
| Quiescent : val abstract_state | Quiescent : val abstract_state
| Updating : loc loc val val val proph_id abstract_state. | Updating : loc loc val val val proph_id abstract_state.
Definition state_to_val (s : abstract_state) : val := Definition state_to_val (s : abstract_state) : val :=
match s with match s with
...@@ -181,17 +217,14 @@ Section rdcss. ...@@ -181,17 +217,14 @@ Section rdcss.
Definition own_token γ := (own γ (Excl ()))%I. Definition own_token γ := (own γ (Excl ()))%I.
Definition pending_state P (n1 : val) (proph_winner : option proph_id) tid_ghost_winner (γ_n γ_a: gname) := Definition pending_state P (n1 : val) (proph_winner : option proph_id) tid_ghost_winner (γ_n γ_a: gname) :=
(P (P from_option (λ p, p = tid_ghost_winner) True proph_winner
match proph_winner with None => True | Some p => p = tid_ghost_winner end own γ_n ( Excl' n1) own_token γ_a)%I.
own γ_n ( Excl' n1)
own_token γ_a)%I.
(* After the prophecy said we are going to win the race, we commit and run the AU, (* After the prophecy said we are going to win the race, we commit and run the AU,
switching from [pending] to [accepted]. *) switching from [pending] to [accepted]. *)
Definition accepted_state Q (proph_winner : option proph_id) (tid_ghost_winner : proph_id) := Definition accepted_state Q (proph_winner : option proph_id) (tid_ghost_winner : proph_id) :=
(( vs, proph tid_ghost_winner vs) (( vs, proph tid_ghost_winner vs)
Q Q from_option (λ p, p = tid_ghost_winner) True proph_winner)%I.
match proph_winner with None => True | Some tid => tid = tid_ghost_winner end)%I.
(* The same thread then wins the CmpXchg and moves from [accepted] to [done]. (* The same thread then wins the CmpXchg and moves from [accepted] to [done].
Then, the [γ_t] token guards the transition to take out [Q]. Then, the [γ_t] token guards the transition to take out [Q].
...@@ -203,7 +236,8 @@ Section rdcss. ...@@ -203,7 +236,8 @@ Section rdcss.
owns *more than* half of its [l_descr] in the Updating state, owns *more than* half of its [l_descr] in the Updating state,
which means we know that the [l_descr] there and here cannot be the same. *) which means we know that the [l_descr] there and here cannot be the same. *)
Definition done_state Qn (l_descr : loc) (tid_ghost_winner : proph_id) (γ_t γ_a: gname) := Definition done_state Qn (l_descr : loc) (tid_ghost_winner : proph_id) (γ_t γ_a: gname) :=
((Qn own_token γ_t) ( vs, proph tid_ghost_winner vs) (l_descr {1/2} -) own_token γ_a)%I. ((Qn own_token γ_t) ( vs, proph tid_ghost_winner vs)
l_descr {1/2} - own_token γ_a)%I.
(* Invariant expressing the descriptor protocol. (* Invariant expressing the descriptor protocol.
- We always need the [proph] in here so that failing threads coming late can - We always need the [proph] in here so that failing threads coming late can
...@@ -252,7 +286,7 @@ Section rdcss. ...@@ -252,7 +286,7 @@ Section rdcss.
(* We own *more than* half of [l_descr], which shows that this cannot (* We own *more than* half of [l_descr], which shows that this cannot
be the [l_descr] of any [descr] protocol in the [done] state. *) be the [l_descr] of any [descr] protocol in the [done] state. *)
val_is_unboxed m1 val_is_unboxed m1
l_descr {1/2 + q} (#l_m, m1, n1, n2, #p)%V l_descr {1/2 + q} (#l_m, m1, n1, n2, #p)%V
inv descrN (descr_inv P Q p n1 l_n l_descr tid_ghost_winner γ_n γ_t γ_s γ_a) inv descrN (descr_inv P Q p n1 l_n l_descr tid_ghost_winner γ_n γ_t γ_s γ_a)
pau P Q γ_n l_m m1 n1 n2 is_gc_loc l_m pau P Q γ_n l_m m1 n1 n2 is_gc_loc l_m
end)%I. end)%I.
...@@ -265,7 +299,7 @@ Section rdcss. ...@@ -265,7 +299,7 @@ Section rdcss.
Global Instance is_rdcss_persistent γ_n l_n: Persistent (is_rdcss γ_n l_n) := _. Global Instance is_rdcss_persistent γ_n l_n: Persistent (is_rdcss γ_n l_n) := _.
Global Instance rdcss_content_timeless γ_n n : Timeless (rdcss_content γ_n n) := _. Global Instance rdcss_content_timeless γ_n n : Timeless (rdcss_content γ_n n) := _.
Global Instance abstract_state_inhabited: Inhabited abstract_state := populate (Quiescent #0). Global Instance abstract_state_inhabited: Inhabited abstract_state := populate (Quiescent #0).
Lemma rdcss_content_exclusive γ_n l_n_1 l_n_2 : Lemma rdcss_content_exclusive γ_n l_n_1 l_n_2 :
...@@ -419,7 +453,7 @@ Section rdcss. ...@@ -419,7 +453,7 @@ Section rdcss.
as a precondition. *) as a precondition. *)
Lemma complete_spec (l_n l_m l_descr : loc) (m1 n1 n2 : val) (p : proph_id) γ_n γ_t γ_s γ_a tid_ghost_inv P Q q: Lemma complete_spec (l_n l_m l_descr : loc) (m1 n1 n2 : val) (p : proph_id) γ_n γ_t γ_s γ_a tid_ghost_inv P Q q:
val_is_unboxed m1 val_is_unboxed m1
N ## gcN N ## gcN
inv rdcssN (rdcss_inv γ_n l_n) - inv rdcssN (rdcss_inv γ_n l_n) -
inv descrN (descr_inv P Q p n1 l_n l_descr tid_ghost_inv γ_n γ_t γ_s γ_a) - inv descrN (descr_inv P Q p n1 l_n l_descr tid_ghost_inv γ_n γ_t γ_s γ_a) -
pau P Q γ_n l_m m1 n1 n2 - pau P Q γ_n l_m m1 n1 n2 -
...@@ -434,7 +468,7 @@ Section rdcss. ...@@ -434,7 +468,7 @@ Section rdcss.
wp_bind (! _)%E. wp_load. iClear "Hld". wp_pures. wp_bind (! _)%E. wp_load. iClear "Hld". wp_pures.
wp_apply wp_new_proph; first done. wp_apply wp_new_proph; first done.
iIntros (vs_ghost tid_ghost) "Htid_ghost". wp_pures. iIntros (vs_ghost tid_ghost) "Htid_ghost". wp_pures.
wp_bind (! _)%E. wp_bind (! _)%E.
(* open outer invariant *) (* open outer invariant *)
iInv rdcssN as (s) "(>Hln & Hrest)"=>//. iInv rdcssN as (s) "(>Hln & Hrest)"=>//.
(* two different proofs depending on whether we are succeeding thread *) (* two different proofs depending on whether we are succeeding thread *)
...@@ -448,7 +482,7 @@ Section rdcss. ...@@ -448,7 +482,7 @@ Section rdcss.
iMod (gc_access with "InvGC") as "Hgc"; first solve_ndisj. iMod (gc_access with "InvGC") as "Hgc"; first solve_ndisj.
(* open and *COMMIT* AU, sync B location l_n and A location l_m *) (* open and *COMMIT* AU, sync B location l_n and A location l_m *)
iMod "AU" as (m' n') "[CC [_ Hclose]]". iMod "AU" as (m' n') "[CC [_ Hclose]]".
iDestruct "CC" as "[Hgc_lm Hn◯]". iDestruct "CC" as "[Hgc_lm Hn◯]".
(* sync B location and update it if required *) (* sync B location and update it if required *)
iDestruct (sync_values with "Hn● Hn◯") as %->. iDestruct (sync_values with "Hn● Hn◯") as %->.
iMod (update_value _ _ _ (if decide (m' = m1 n' = n') then n2 else n') with "Hn● Hn◯") iMod (update_value _ _ _ (if decide (m' = m1 n' = n') then n2 else n') with "Hn● Hn◯")
...@@ -509,9 +543,9 @@ Section rdcss. ...@@ -509,9 +543,9 @@ Section rdcss.
<<< gc_mapsto l_m m rdcss_content γ_n (if decide (m = m1 n = n1) then n2 else n), RET n >>>. <<< gc_mapsto l_m m rdcss_content γ_n (if decide (m = m1 n = n1) then n2 else n), RET n >>>.
Proof. Proof.
iIntros (Hm1_unbox Hn1_unbox) "Hrdcss". iDestruct "Hrdcss" as "(#InvR & #InvGC & Hdisj)". iIntros (Hm1_unbox Hn1_unbox) "Hrdcss". iDestruct "Hrdcss" as "(#InvR & #InvGC & Hdisj)".
iDestruct "Hdisj" as %Hdisj. iIntros (Φ) "AU". iDestruct "Hdisj" as %Hdisj. iIntros (Φ) "AU".
(* allocate fresh descriptor *) (* allocate fresh descriptor *)
wp_lam. wp_pures. wp_lam. wp_pures.
wp_apply wp_new_proph; first done. wp_apply wp_new_proph; first done.
iIntros (proph_values p) "Hp". iIntros (proph_values p) "Hp".
wp_let. wp_alloc l_descr as "Hld". wp_let. wp_alloc l_descr as "Hld".
...@@ -549,12 +583,12 @@ Section rdcss. ...@@ -549,12 +583,12 @@ Section rdcss.
iModIntro. iDestruct "Hld" as "[Hld1 [Hld2 Hld3]]". iSplitR "Hld2 Token_t". iModIntro. iDestruct "Hld" as "[Hld1 [Hld2 Hld3]]". iSplitR "Hld2 Token_t".
{ (* close outer invariant *) { (* close outer invariant *)
iNext. iCombine "Hld1 Hld3" as "Hld1". iExists (Updating l_descr l_m m1 n n2 p). iNext. iCombine "Hld1 Hld3" as "Hld1". iExists (Updating l_descr l_m m1 n n2 p).
eauto 15 with iFrame. eauto 15 with iFrame.
} }
wp_pures. wp_pures.
wp_apply (complete_spec with "[] [] [] [] [] [$Hld2]");[ done..|]. wp_apply (complete_spec with "[] [] [] [] [] [$Hld2]");[ done..|].
iIntros "Ht". iMod ("Ht" with "Token_t") as "Φ". by wp_seq. iIntros "Ht". iMod ("Ht" with "Token_t") as "Φ". by wp_seq.
+ (* values do not match -> CmpXchg fails + (* values do not match -> CmpXchg fails
we can commit here *) we can commit here *)
wp_cmpxchg_fail. wp_cmpxchg_fail.
iMod "AU" as (m'' n'') "[[Hm◯ Hn◯] [_ Hclose]]"; simpl. iMod "AU" as (m'' n'') "[[Hm◯ Hn◯] [_ Hclose]]"; simpl.
...@@ -568,7 +602,7 @@ Section rdcss. ...@@ -568,7 +602,7 @@ Section rdcss.
- (* l_n ↦ injR l_ndescr' *) - (* l_n ↦ injR l_ndescr' *)
(* a descriptor l_descr' is currently stored at l_n -> CmpXchg fails (* a descriptor l_descr' is currently stored at l_n -> CmpXchg fails
try to help the on-going operation *) try to help the on-going operation *)
wp_cmpxchg_fail. wp_cmpxchg_fail.
iModIntro. iModIntro.
(* extract descr invariant *) (* extract descr invariant *)
iDestruct "Hrest" as (q P Q tid_ghost γ_t γ_s γ_a) "(#Hm1'_unbox & [Hld1 [Hld2 Hld3]] & #InvS & #P_AU & #P_GC)". iDestruct "Hrest" as (q P Q tid_ghost γ_t γ_s γ_a) "(#Hm1'_unbox & [Hld1 [Hld2 Hld3]] & #InvS & #P_AU & #P_GC)".
...@@ -600,7 +634,7 @@ Section rdcss. ...@@ -600,7 +634,7 @@ Section rdcss.
iExists (Quiescent n). iFrame. } iExists (Quiescent n). iFrame. }
iModIntro. iModIntro.
iApply ("HΦ" $! l_n γ_n). iApply ("HΦ" $! l_n γ_n).
iSplitR; last by iFrame. by iFrame "#". iSplitR; last by iFrame. by iFrame "#".
Qed. Qed.
(** ** Proof of [get] *) (** ** Proof of [get] *)
...@@ -611,7 +645,7 @@ Section rdcss. ...@@ -611,7 +645,7 @@ Section rdcss.
<<< rdcss_content γ_n n, RET n >>>. <<< rdcss_content γ_n n, RET n >>>.
Proof. Proof.
iIntros "Hrdcss". iDestruct "Hrdcss" as "(#InvR & #InvGC & Hdisj)". iIntros "Hrdcss". iDestruct "Hrdcss" as "(#InvR & #InvGC & Hdisj)".
iDestruct "Hdisj" as %Hdisj. iIntros (Φ) "AU". iDestruct "Hdisj" as %Hdisj. iIntros (Φ) "AU".
iLöb as "IH". wp_lam. repeat (wp_proj; wp_let). wp_bind (! _)%E. iLöb as "IH". wp_lam. repeat (wp_proj; wp_let). wp_bind (! _)%E.
iInv rdcssN as (s) "(>Hln & Hrest)". iInv rdcssN as (s) "(>Hln & Hrest)".
wp_load. wp_load.
...@@ -619,7 +653,7 @@ Section rdcss. ...@@ -619,7 +653,7 @@ Section rdcss.
- iMod "AU" as (au_n) "[Hn◯ [_ Hclose]]"; simpl. - iMod "AU" as (au_n) "[Hn◯ [_ Hclose]]"; simpl.
iDestruct "Hrest" as "[Hln' Hn●]". iDestruct "Hrest" as "[Hln' Hn●]".
iDestruct (sync_values with "Hn● Hn◯") as %->. iDestruct (sync_values with "Hn● Hn◯") as %->.
iMod ("Hclose" with "Hn◯") as "HΦ". iMod ("Hclose" with "Hn◯") as "HΦ".
iModIntro. iSplitR "HΦ". { iModIntro. iSplitR "HΦ". {
iNext. iExists (Quiescent au_n). iFrame. iNext. iExists (Quiescent au_n). iFrame.
} }
...@@ -627,9 +661,9 @@ Section rdcss. ...@@ -627,9 +661,9 @@ Section rdcss.
- iDestruct "Hrest" as (q P Q tid_ghost γ_t γ_s γ_a) "(#Hm1_unbox & [Hld [Hld' Hld'']] & #InvS & #PAU & #GC)". - iDestruct "Hrest" as (q P Q tid_ghost γ_t γ_s γ_a) "(#Hm1_unbox & [Hld [Hld' Hld'']] & #InvS & #PAU & #GC)".
iDestruct "Hm1_unbox" as %Hm1_unbox. iDestruct "Hm1_unbox" as %Hm1_unbox.
iModIntro. iSplitR "AU Hld'". { iModIntro. iSplitR "AU Hld'". {
iNext. iExists (Updating l_descr l_m m1 n1 n2 p). eauto 15 with iFrame. iNext. iExists (Updating l_descr l_m m1 n1 n2 p). eauto 15 with iFrame.
} }
wp_match. wp_match.
wp_apply (complete_spec with "[] [] [] [] [] [$Hld']"); [done..|]. wp_apply (complete_spec with "[] [] [] [] [] [$Hld']"); [done..|].
iIntros "Ht". wp_seq. iApply "IH". iApply "AU". iIntros "Ht". wp_seq. iApply "IH". iApply "AU".
Qed. Qed.
......
...@@ -4,7 +4,14 @@ From iris.program_logic Require Export atomic. ...@@ -4,7 +4,14 @@ From iris.program_logic Require Export atomic.
From iris_examples.logatom.lib Require Export gc. From iris_examples.logatom.lib Require Export gc.
Set Default Proof Using "Type". Set Default Proof Using "Type".
(** A general logically atomic interface for conditional increment. *) (** A general logically atomic interface for RDCSS.
See [rdcss.v] for references and more details about this data structure. *)
_Note on the use of GC locations_: the specification of the [rdcss] operation
as given by [rdcss_spec] relies on the [gc_mapsto l_m m] assertion. It roughly
corresponds to the usual [l_m m] but with an additional guarantee that [l_m]
will not be deallocated. This guarantees that unique immutable descriptors can
be associated to each operation, and that they cannot be "reused". *)
Record atomic_rdcss {Σ} `{!heapG Σ, !gcG Σ} := AtomicRdcss { Record atomic_rdcss {Σ} `{!heapG Σ, !gcG Σ} := AtomicRdcss {
(* -- operations -- *) (* -- operations -- *)
new_rdcss : val; new_rdcss : val;
...@@ -42,7 +49,6 @@ Record atomic_rdcss {Σ} `{!heapG Σ, !gcG Σ} := AtomicRdcss { ...@@ -42,7 +49,6 @@ Record atomic_rdcss {Σ} `{!heapG Σ, !gcG Σ} := AtomicRdcss {
}. }.
Arguments atomic_rdcss _ {_} {_}. Arguments atomic_rdcss _ {_} {_}.
Existing Instances Existing Instances
is_rdcss_persistent rdcss_content_timeless is_rdcss_persistent rdcss_content_timeless
name_countable name_eqdec. name_countable name_eqdec.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment