Section JuicyMachineShell.
Context {Sem: Semantics}.
Notation C:= (semC).
Notation G:= (semG).
Notation tid:= nat.
Notation lockMap:= (AMap.t lock_info).
Notation SSome x:= (Some (Some x)).
Notation SNone:= (Some None).
(** Memories*)
Definition richMem: Type:= juicy_mem.
Definition dryMem: richMem -> mem:= m_dry.
(** Environment and Threadwise semantics *)
(* This all comes from the SEM. *)
(*Parameter G : Type. Parameter Sem : CoreSemantics G code mem.*)
Notation the_sem := (csem (event_semantics.msem semSem)).
(*thread pool*)
Existing Instance OrdinalThreadPool.
Notation thread_pool := (@ThreadPool.t _ _ OrdinalThreadPool).
(** Machine Variables*)
Definition lp_id : tid:= (0)%nat. (*lock pool thread id*)
(** Invariants*)
(** The state respects the memory*)
Definition access_cohere' m phi:= forall loc,
Mem.perm_order'' (max_access_at m loc) (perm_of_res (phi @ loc)).
(* This is similar to the coherence of juicy memories, * * but for entire machines. It is slighly weaker in one way: * - acc_coh is looser and only talks about maxcoh. * - alse acc_coh  might me redundant with max_coh IDK... x*)
Record mem_cohere' m phi :=
{ cont_coh: contents_cohere m phi;
(*acc_coh: access_cohere m phi;*)
(*acc_coh: access_cohere' m phi;*)
max_coh: max_access_cohere m phi;
all_coh: alloc_cohere m phi
}.
Definition mem_thcohere (tp : thread_pool) m :=
forall tid (cnt: containsThread tp tid), mem_cohere' m (getThreadR cnt).
Definition mem_lock_cohere (ls:lockMap) m:=
forall loc rm, AMap.find loc ls = SSome rm -> mem_cohere' m rm.
(*Join juice from all threads *)
Definition getThreadsR (tp : thread_pool):=
map (perm_maps tp) (enums_equality.enum (num_threads tp)).
Fixpoint join_list (ls: seq.seq res) r:=
if ls is phi::ls' then exists r', join phi r' r /\ join_list ls' r' else
app_pred emp r.  (*Or is is just [amp r]?*)
Definition join_threads (tp : thread_pool) r:= join_list (getThreadsR tp) r.
(*Join juice from all locks*)
Fixpoint join_list' (ls: seq.seq (option res)) (r:option res):=
if ls is phi::ls' then exists (r':option res),
@join _ (@Join_lower res _) phi r' r /\ join_list' ls' r' else r=None.
Definition join_locks tp r:= join_list' (map snd (AMap.elements (lset tp))) r.
(*Join all the juices*)
Inductive join_all: thread_pool -> res -> Prop:=
AllJuice tp r0 r1 r:
join_threads tp r0 ->
join_locks tp r1 ->
join (Some r0) r1 (Some r) ->
join_all tp r.
Definition juicyLocks_in_lockSet (lset : lockMap) (juice: rmap):=
forall loc,
(forall i, 0 <= i < LKSIZE -> exists sh psh P, juice @ (fst loc, snd loc + i) = YES sh psh (LK LKSIZE i) P)  ->
AMap.find loc lset.
(* I removed the NO case for two reasons: * - To ensure that lset is "valid" (lr_valid), it needs inherit it from the rmap * - there was no real reason to have a NO other than speculation of the future. *)
Definition lockSet_in_juicyLocks (lset : lockMap) (juice: rmap):=
forall loc, AMap.find loc lset ->
(exists sh,
forall i, 0 <= i < LKSIZE -> exists sh' psh' P, join_sub sh sh' /\ juice @ (fst loc, snd loc + i) = YES sh' psh' (LK LKSIZE i) P).
Definition lockSet_in_juicyLocks' (lset : lockMap) (juice: rmap):=
forall loc, AMap.find loc lset ->
Mem.perm_order'' (Some Nonempty) (perm_of_res (juice @ loc)).
Definition lockSet_Writable (lset : lockMap) m :=
forall b ofs, AMap.find (b,ofs) lset ->
forall ofs0, Intv.In ofs0 (ofs, ofs + LKSIZE)%Z ->
Mem.perm_order'' ((Mem.mem_access m)!! b ofs0 Max) (Some Writable) .
(*This definition makes no sense. In fact if there is at least one lock in rmap, *then the locks_writable is false (because perm_of_res(LK) = Some Nonempty). *)
Definition locks_writable (juice: rmap):=
forall loc sh psh P z i, juice @ loc = YES sh psh (LK z i) P  ->
Mem.perm_order'' (perm_of_res (juice @ loc)) (Some Writable).
Record mem_compatible_with' (tp : thread_pool) m all_juice : Prop :=
{   juice_join : join_all tp all_juice
; all_cohere : mem_cohere' m all_juice
; loc_writable : lockSet_Writable (lockGuts tp) m
; jloc_in_set : juicyLocks_in_lockSet (lockGuts tp) all_juice
; lset_in_juice: lockSet_in_juicyLocks  (lockGuts tp) all_juice
}.
Definition mem_compatible_with := mem_compatible_with'.
Definition mem_compatible tp m := ex (mem_compatible_with tp m).
(* Lemma mem_compatible_locks_lt: forall {tp m}, mem_compatible tp m -> forall i cnti, permMapLt (perm_of_res_lock (@getThreadR i tp cnti)) (getMaxPerm m ).  Lemma compat_lt_m: forall m js, mem_compatible js m -> forall b ofs, Mem.perm_order'' ((getMaxPerm m) !! b ofs) ((lockSet js) !! b ofs).  (** There is no inteference in the thread pool *)
(* Per-thread disjointness definition*)
Definition disjoint_threads tp :=
forall i j (cnti : containsThread tp i)
(cntj: containsThread tp j) (Hneq: i <> j),
joins (getThreadR(resources:=LocksAndResources) cnti)
(getThreadR cntj).
(* Per-lock disjointness definition*)
Definition disjoint_locks tp :=
forall loc1 loc2 r1 r2,
lockRes tp loc1 = SSome r1 ->
lockRes tp loc2 = SSome r2 ->
joins r1 r2.
(* lock-thread disjointness definition*)
Definition disjoint_lock_thread tp :=
forall i loc r (cnti : containsThread tp i),
lockRes tp loc = SSome r ->
joins (getThreadR cnti)r.
Variant invariant' (tp:t) := True. (* The invariant has been absorbed my mem_compat*)
(* { no_race : disjoint_threads tp }.*)
Definition invariant := invariant'.
(*Lemmas to retrive the ex-invariant properties from the mem-compat*)
(** Steps*)
(* What follows is the lemmas needed to construct a "personal" memory That is a memory with the juice and Cur of a particular thread. *)
Definition mapmap {A B} (def:B) (f:positive -> A -> B) (m:PMap.t A): PMap.t B:=
(def, PTree.map f m#2).
(* You need the memory, to make a finite tree. *)
Definition juice2Perm (phi:rmap)(m:mem): access_map:=
mapmap (fun _ => None) (fun block _ => fun ofs => perm_of_res (phi @ (block, ofs)) ) (getMaxPerm m).
Definition juice2Perm_locks (phi:rmap)(m:mem): access_map:=
mapmap (fun _ => None) (fun block _ => fun ofs => perm_of_res_lock (phi @ (block, ofs)) ) (getMaxPerm m).

Lemma juic2Perm_correct:
forall r m b ofs,
access_cohere' m r ->
perm_of_res (r @ (b,ofs)) = (juice2Perm r m) !! b ofs.