(*+ Oracular semantics *)

(** Single-thread oracular semantics: each thread assumes that the
    oracle provides maps satisfying the invariants, but the thread
    also have to give back maps that satisfy those invariants. *)

Record globals := mkglobals
  { resinvs : nat -> pred (* resource invariant for each lock *) ;
    funspecs : string -> option pred (* precondition of each function *)
  }.(*+ Oracular semantics *)

(** Single-thread oracular semantics: each thread assumes that the
    oracle provides maps satisfying the invariants, but the thread
    also have to give back maps that satisfy those invariants. *)

Record globals := mkglobals
  { resinvs : nat -> pred (* resource invariant for each lock *) ;
    funspecs : string -> option pred (* precondition of each function *)
  }.(*+ Oracular semantics *)

(** Single-thread oracular semantics: each thread assumes that the
    oracle provides maps satisfying the invariants, but the thread
    also have to give back maps that satisfy those invariants. *)

Record globals := mkglobals
  { resinvs : nat -> pred (* resource invariant for each lock *) ;
    funspecs : string -> option pred (* precondition of each function *)
  }.(*+ Oracular semantics *)

(** Single-thread oracular semantics: each thread assumes that the
    oracle provides maps satisfying the invariants, but the thread
    also have to give back maps that satisfy those invariants. *)

Record globals := mkglobals
  { resinvs : nat -> pred (* resource invariant for each lock *) ;
    funspecs : string -> option pred (* precondition of each function *)
  }.Definition oracle := list map.(*+ Concurrent machine *)

(** Semantics of the collection of all threads. Thread and locked
    locks each have their own map. *)

Definition schedule := list nat.Definition threads := list (map * list instruction).Definition lockpool := nat -> option map.Definition functions := string -> option (list instruction).Definition config := (schedule * functions * globals * threads * lockpool)%type.(*+ Collection of disjoint maps *)

(** For the proof of composition of safety, we need to maintain the
    invariants "all the maps are disjoint*" which is why we need this
    section.

  * pairwise-disjointness is equivalent to arbitrary disjointness
    because the permissions are "set-theoretical" *)

Definition selfjoins {A} (maps : A -> map) :=
  forall i j, i <> j -> joins (maps i) (maps j).Definition sameperms (m n : map) := forall x, m x = None <-> n x = None.

(* Specifications: *)
Lemma sameperms_refl m : sameperms m m.
Lemma sameperms_sym m n : sameperms m n -> sameperms n m.
Lemma sameperms_trans m n o : sameperms m n -> sameperms n o -> sameperms m o.
Lemma sameperms_updatemap m x e m' : updatemap m x e = Some m' -> sameperms m m'.
Lemma sameperms_joins m m' n : sameperms m m' -> joins m n -> joins m' n.
Lemma selfjoins_sameperms_compat {A} maps1 maps2 : (forall i:A, sameperms (maps1 i) (maps2 i)) -> selfjoins maps1 -> selfjoins maps2.