(*+ Composing safety of several threads *)

(** If each thread behaves well (assuming a good oracle) then running
    those threads in a concurrent machine is safe, too.  The proof
    builds a good oracle for each thread so that each thread follows
    the steps of the machine. *)

Definition lockpool_matches (pool : lockpool) RI :=
  forall l, match pool l with Some m => m |= RI l | None => True end.Definition functions_safe G F :=
  forall f, match funspecs G f, F f with
       | Some P, Some p =>
         forall m oracle, P m -> safe step (G, oracle, m, p)
       | None, None => True
       | _, _ => False
       end.Ltac funspecs_inv :=
  match goal with
  | FF : functions_safe ?G ?F |- _ =>
    match goal with
    | FSf : funspecs G ?f = Some _ |- _ =>
      let H := fresh "Hsafe" in
      let p := fresh "p" in
      let E := fresh "E" in
      pose proof FF f as H;
      destruct (F f) as [p|] eqn:E;
      rewrite FSf in H; [|tauto]
    | Ff : F ?f = Some _ |- _ =>
      let H := fresh "Hsafe" in
      let P := fresh "PRE" in
      let E := fresh "E" in
      pose proof FF f as H;
      destruct (funspecs G f) as [P|] eqn:E;
      rewrite Ff in H; [|tauto]
    end
  end.(* Our invariant:
 - resource invariants are precise (no need for them to be positive)
 - all the functions are safe (given a precondition)
 - lock pool maps and threads maps are disjoint
 - lock pool maps match the resource invariants
 - all threads are safe for n steps
*)

Definition P (x : config) :=
  match x with (_, F, G, thd, pool) =>
    (forall l, precise (resinvs G l)) /\
    functions_safe G F /\
    selfjoins (reindex thd pool) /\
    lockpool_matches pool (resinvs G) /\
    (forall i oracle m p,
        nth thd i = Some (m, p) ->
        safe step (G, oracle, m, p))
  end.

Theorem jsafeN_versus_step_safeN_ n z c m G : safeN_ oracle_at_ext_old n z c m -> safe_ n step (G, z, m, c).