(*+ Small concurrent stack *)
(** In this file: - a single-theaded semantics (with oracle and invariants) - a multi-thread concurrent machine (with schedule and invariants) - proof that the safety of all threads implies the safety of the machine - a hoare logic implying safety in the oracle semantics - a small example yielding safety of the corresponding machine *)
(* we can remove the need for functional extensionality, at the expense of heavier definitions and proofs, with [m |= P] defined as [forall m', eqmap m m' -> P m'] instead of [P m] *)
(*+ Syntax *)
Inductive instruction :=
| set (x e:nat)      (* mem[x] := e *)
| assert (x:nat)     (* assert mem[x]<>0 *)
| release (l:nat)    (* unlocking a lock *)
| acquire (l:nat)    (* locking a lock *)
| spawn (f:string) (* spawning function f *).
(** spawning could be replaced with  | spawn (p : list instruction)  and then when reaching it in the oracular semantics, the oracle says how the current map is split [NO! the oracle would say which map you're given when you do JOIN, but the safety of the thread has to provide which map to give away], and then the oracle itself is (interleaving)-split into two.  We could also write  | par (p1 p2 : list instruction)  and do the same.  We adopt the spawning with an ID instead because it's closer to the architecture of VST *)
(*+ General results about safety *)
Definition Rel X := X -> X -> Prop.
Inductive star {X} (R : Rel X) : Rel X :=
| star_refl x : star R x x
| star_cons x y z : R x y -> star R y z -> star R x z.
Definition safe {X} (R : Rel X) x := forall y, star R x y -> exists z, R y z.
(*! Indexed version of safety (not needed here) *)
Inductive iter {X} (R : Rel X) : nat -> Rel X :=
| iter_O x : iter R O x x
| iter_S n x y z : R x y -> iter R n y z -> iter R (S n) x z.
Definition safe_ n {X} (R : Rel X) x := forall y m, m < n -> iter R m x y -> exists z, R y z.
(*+ Stdlib: some list functions *)
Fixpoint nth {A} (l : list A) i :=
match l with
| nil => None
| x :: l =>
match i with
| O => Some x
| S i => nth l i
end
end.
Fixpoint nth_upd {A} (l : list A) i x :=
match l with
| nil => nil
| y :: l =>
match i with
| O => x :: l
| S i => y :: nth_upd l i x
end
end.
Ltac ifeq :=
match goal with
[ H : context [ eq_nat_dec ?x ?x ] |- _ ] => destruct (eq_nat_dec x x) as [_|]; [|congruence]
| [ |- context [ eq_nat_dec ?x ?x ] ] => destruct (eq_nat_dec x x) as [_|]; [|congruence]
| [ H : context [ eq_nat_dec ?x ?y ] |- _ ] => destruct (eq_nat_dec x y)
| [ |- context [ eq_nat_dec ?x ?y ] ] => destruct (eq_nat_dec x y)
end.
(*+ Memory maps *)
Definition map := nat -> option nat.
Definition emptymap : map := fun _ => None.
Definition eqmap (m m' : map) := forall x, m x = m' x.
Instance eqmap_equiv : Equivalence eqmap.
Definition upd {A} (m : nat -> A) x e :=
fun y => if eq_nat_dec x y then e else m y.
Definition updatemap (m : map) (x e : nat) : option map :=
match m x with Some _ => Some (upd m x (Some e)) | None => None end.
Definition assertmap (m : map) (x : nat) : Prop :=
match m x with Some (S _) => True | _ => False end.
Definition joincell (a b : option nat) : option (option nat) :=
match a, b with
| None, None => Some None
| Some a, None | None, Some a => Some (Some a)
| Some _, Some _ => None
end.
Definition join (m n o : map) : Prop := forall x, joincell (m x) (n x) = Some (o x).
Definition joins (m n : map) : Prop := exists o, join m n o.
Add Parametric Morphism : join with signature eqmap ==> eqmap ==> eqmap ==> iff as join_morphism.

Lemma join_eqmap_compat_l {m m' n o}  : eqmap m m' -> join m n o -> join m' n o.