Theory ExternalCallWF

(*  Title:      JinjaThreads/Common/ExternalCallWF.thy
    Author:     Andreas Lochbihler
*)

section ‹Properties of external calls in well-formed programs›

theory ExternalCallWF
imports
  WellForm
  "../Framework/FWSemantics"
begin

lemma external_WT_defs_is_type:
  assumes "wf_prog wf_md P" and "CM(Ts) :: T"
  shows "is_class P C" and "is_type P T" "set Ts  types P"
using assms by(auto elim: external_WT_defs.cases)

context heap_base begin

lemma WT_red_external_aggr_imp_red_external:
  " wf_prog wf_md P; (ta, va, h')  red_external_aggr P t a M vs h; P,h  aM(vs) : U; P,h  t √t 
   P,t  aM(vs), h -ta→ext va, h'"
apply(drule tconfD)
apply(erule external_WT'.cases)
apply(clarsimp)
apply(drule (1) sees_wf_native)
apply(erule external_WT_defs.cases)
apply(case_tac [!] hT)
apply(auto 4 4 simp add: red_external_aggr_def widen_Class intro: red_external.intros heap_base.red_external.intros[where addr2thread_id=addr2thread_id and thread_id2addr=thread_id2addr and spurious_wakeups=True and empty_heap=empty_heap and allocate=allocate and typeof_addr=typeof_addr and heap_read=heap_read and heap_write=heap_write] heap_base.red_external.intros[where addr2thread_id=addr2thread_id and thread_id2addr=thread_id2addr and spurious_wakeups=False and empty_heap=empty_heap and allocate=allocate and typeof_addr=typeof_addr and heap_read=heap_read and heap_write=heap_write] split: if_split_asm dest: sees_method_decl_above)
done

lemma WT_red_external_list_conv:
  " wf_prog wf_md P; P,h  aM(vs) : U; P,h  t √t 
   P,t  aM(vs), h -ta→ext va, h'  (ta, va, h')  red_external_aggr P t a M vs h"
by(blast intro: WT_red_external_aggr_imp_red_external red_external_imp_red_external_aggr)

lemma red_external_new_thread_sees:
  " wf_prog wf_md P; P,t  aM(vs), h -ta→ext va, h'; NewThread t' (C, M', a') h''  set tat 
   typeof_addr h' a' = Class_type C  (T meth D. P  C sees M':[]T = meth in D)"
by(fastforce elim!: red_external.cases simp add: widen_Class ta_upd_simps dest: sub_Thread_sees_run)

end

subsection ‹Preservation of heap conformance›

context heap_conf_read begin

lemma hconf_heap_copy_loc_mono:
  assumes "heap_copy_loc a a' al h obs h'"
  and "hconf h"
  and "P,h  a@al : T" "P,h  a'@al : T"
  shows "hconf h'"
proof -
  from heap_copy_loc a a' al h obs h' obtain v
    where read: "heap_read h a al v"
    and "write": "heap_write h a' al v h'" by cases auto
  from read P,h  a@al : T hconf h have "P,h  v :≤ T"
    by(rule heap_read_conf)
  with "write" hconf h P,h  a'@al : T show ?thesis
    by(rule hconf_heap_write_mono)
qed

lemma hconf_heap_copies_mono:
  assumes "heap_copies a a' als h obs h'"
  and "hconf h"
  and "list_all2 (λal T. P,h  a@al : T) als Ts"
  and "list_all2 (λal T. P,h  a'@al : T) als Ts"
  shows "hconf h'"
using assms
proof(induct arbitrary: Ts)
  case Nil thus ?case by simp
next
  case (Cons al h ob h' als obs h'')
  note step = heap_copy_loc a a' al h ob h'
  from list_all2 (λal T. P,h  a@al : T) (al # als) Ts
  obtain T Ts' where [simp]: "Ts = T # Ts'"
    and "P,h  a@al : T" "list_all2 (λal T. P,h  a@al : T) als Ts'"
    by(auto simp add: list_all2_Cons1)
  from list_all2 (λal T. P,h  a'@al : T) (al # als) Ts
  have "P,h  a'@al : T" "list_all2 (λal T. P,h  a'@al : T) als Ts'" by simp_all
  from step hconf h P,h  a@al : T P,h  a'@al : T
  have "hconf h'" by(rule hconf_heap_copy_loc_mono)
  moreover from step have "h  h'" by(rule hext_heap_copy_loc)
  from list_all2 (λal T. P,h  a@al : T) als Ts'
  have "list_all2 (λal T. P,h'  a@al : T) als Ts'"
    by(rule list_all2_mono)(rule addr_loc_type_hext_mono[OF _ h  h'])
  moreover from list_all2 (λal T. P,h  a'@al : T) als Ts'
  have "list_all2 (λal T. P,h'  a'@al : T) als Ts'"
    by(rule list_all2_mono)(rule addr_loc_type_hext_mono[OF _ h  h'])
  ultimately show ?case by(rule Cons)
qed

lemma hconf_heap_clone_mono:
  assumes "heap_clone P h a h' res"
  and "hconf h"
  shows "hconf h'"
using heap_clone P h a h' res
proof cases
  case CloneFail thus ?thesis using hconf h
    by(fastforce intro: hconf_heap_ops_mono dest: typeof_addr_is_type)
next
  case (ObjClone C h'' a' FDTs obs)
  note FDTs = P  C has_fields FDTs
  let ?als = "map (λ((F, D), Tfm). CField D F) FDTs"
  let ?Ts = "map (λ(FD, T). fst (the (map_of FDTs FD))) FDTs"
  note heap_copies a a' ?als h'' obs h'
  moreover from typeof_addr h a = Class_type C hconf h have "is_class P C"
    by(auto dest: typeof_addr_is_type)
  from (h'', a')  allocate h (Class_type C) have "h  h''" "hconf h''"
    by(rule hext_heap_ops hconf_allocate_mono)+(simp_all add: hconf h is_class P C)
  note hconf h''
  moreover
  from typeof_addr h a = Class_type C FDTs
  have "list_all2 (λal T. P,h  a@al : T) ?als ?Ts"
    unfolding list_all2_map1 list_all2_map2 list_all2_same
    by(fastforce intro: addr_loc_type.intros simp add: has_field_def dest: weak_map_of_SomeI)
  hence "list_all2 (λal T. P,h''  a@al : T) ?als ?Ts"
    by(rule list_all2_mono)(rule addr_loc_type_hext_mono[OF _ h  h''])
  moreover from (h'', a')  allocate h (Class_type C) is_class P C
  have "typeof_addr h'' a' = Class_type C" by(auto dest: allocate_SomeD)
  with FDTs have "list_all2 (λal T. P,h''  a'@al : T) ?als ?Ts"
    unfolding list_all2_map1 list_all2_map2 list_all2_same
    by(fastforce intro: addr_loc_type.intros simp add: has_field_def dest: weak_map_of_SomeI)
  ultimately have "hconf h'" by(rule hconf_heap_copies_mono)
  thus ?thesis using ObjClone by simp
next
  case (ArrClone T n h'' a' FDTs obs)
  let ?als = "map (λ((F, D), Tfm). CField D F) FDTs @ map ACell [0..<n]"
  let ?Ts = "map (λ(FD, T). fst (the (map_of FDTs FD))) FDTs @ replicate n T"
  note heap_copies a a' ?als h'' obs h'
  moreover from typeof_addr h a = Array_type T n hconf h have "is_type P (T⌊⌉)"
    by(auto dest: typeof_addr_is_type)
  from (h'', a')  allocate h (Array_type T n) have "h  h''" "hconf h''"
    by(rule hext_heap_ops hconf_allocate_mono)+(simp_all add: hconf h is_type P (T⌊⌉)[simplified])
  note hconf h''
  moreover from h  h'' typeof_addr h a = Array_type T n
  have type'a: "typeof_addr h'' a = Array_type T n" by(auto intro: hext_arrD)
  note FDTs = P  Object has_fields FDTs
  from type'a FDTs have "list_all2 (λal T. P,h''  a@al : T) ?als ?Ts"
    by(fastforce intro: list_all2_all_nthI addr_loc_type.intros simp add: has_field_def distinct_fst_def list_all2_append list_all2_map1 list_all2_map2 list_all2_same dest: weak_map_of_SomeI)
  moreover from (h'', a')  allocate h (Array_type T n) is_type P (T⌊⌉)
  have "typeof_addr h'' a' = Array_type T n" by(auto dest: allocate_SomeD)
  hence "list_all2 (λal T. P,h''  a'@al : T) ?als ?Ts" using FDTs
    by(fastforce intro: list_all2_all_nthI addr_loc_type.intros simp add: has_field_def distinct_fst_def list_all2_append list_all2_map1 list_all2_map2 list_all2_same dest: weak_map_of_SomeI)
  ultimately have "hconf h'" by(rule hconf_heap_copies_mono)
  thus ?thesis using ArrClone by simp
qed

theorem external_call_hconf:
  assumes major: "P,t  aM(vs), h -ta→ext va, h'"
  and minor: "P,h  aM(vs) : U" "hconf h"
  shows "hconf h'"
using major minor
by cases(fastforce intro: hconf_heap_clone_mono)+

end

context heap_base begin

primrec conf_extRet :: "'m prog  'heap  'addr extCallRet  ty  bool" where
  "conf_extRet P h (RetVal v) T = (P,h  v :≤ T)"
| "conf_extRet P h (RetExc a) T = (P,h  Addr a :≤ Class Throwable)"
| "conf_extRet P h RetStaySame T = True"

end

context heap_conf begin

lemma red_external_conf_extRet:
  assumes wf: "wf_prog wf_md P"
  shows "P,t  aM(vs), h -ta→ext va, h'; P,h  aM(vs) : U; hconf h; preallocated h; P,h  t √t 
   conf_extRet P h' va U"
using wf apply -
apply(frule red_external_hext)
apply(drule (1) preallocated_hext)
apply(auto elim!: red_external.cases external_WT'.cases external_WT_defs_cases dest!: sees_wf_native[OF wf])
apply(auto simp add: conf_def tconf_def intro: xcpt_subcls_Throwable dest!: hext_heap_write)
apply(case_tac hT)
apply(auto 4 4 dest!: typeof_addr_heap_clone dest: typeof_addr_is_type intro: widen_array_object subcls_C_Object)
done

end

subsection ‹Progress theorems for external calls›

context heap_progress begin

lemma heap_copy_loc_progress:
  assumes hconf: "hconf h"
  and alconfa: "P,h  a@al : T"
  and alconfa': "P,h  a'@al : T"
  shows "v h'. heap_copy_loc a a' al h ([ReadMem a al v, WriteMem a' al v]) h'  P,h  v :≤ T  hconf h'"
proof -
  from heap_read_total[OF hconf alconfa]
  obtain v where "heap_read h a al v" "P,h  v :≤ T" by blast
  moreover from heap_write_total[OF hconf alconfa' P,h  v :≤ T] obtain h' where "heap_write h a' al v h'" ..
  moreover hence "hconf h'" using hconf alconfa' P,h  v :≤ T by(rule hconf_heap_write_mono)
  ultimately show ?thesis by(blast intro: heap_copy_loc.intros)
qed

lemma heap_copies_progress:
  assumes "hconf h"
  and "list_all2 (λal T. P,h  a@al : T) als Ts"
  and "list_all2 (λal T. P,h  a'@al : T) als Ts"
  shows "vs h'. heap_copies a a' als h (concat (map (λ(al, v). [ReadMem a al v, WriteMem a' al v]) (zip als vs))) h'  hconf h'"
using assms
proof(induct als arbitrary: h Ts)
  case Nil thus ?case by(auto intro: heap_copies.Nil)
next
  case (Cons al als)
  from list_all2 (λal T. P,h  a@al : T) (al # als) Ts
  obtain T' Ts' where [simp]: "Ts = T' # Ts'"
    and "P,h  a@al : T'" "list_all2 (λal T. P,h  a@al : T) als Ts'"
    by(auto simp add: list_all2_Cons1)
  from list_all2 (λal T. P,h  a'@al : T) (al # als) Ts
  have "P,h  a'@al : T'" and "list_all2 (λal T. P,h  a'@al : T) als Ts'" by simp_all
  from hconf h P,h  a@al : T' P,h  a'@al : T'
  obtain v h' where "heap_copy_loc a a' al h [ReadMem a al v, WriteMem a' al v] h'"
    and "hconf h'" by(fastforce dest: heap_copy_loc_progress)
  moreover hence "h  h'" by-(rule hext_heap_copy_loc)
  {
    note hconf h'
    moreover from list_all2 (λal T. P,h  a@al : T) als Ts'
    have "list_all2 (λal T. P,h'  a@al : T) als Ts'"
      by(rule list_all2_mono)(rule addr_loc_type_hext_mono[OF _ h  h'])
    moreover from list_all2 (λal T. P,h  a'@al : T) als Ts'
    have "list_all2 (λal T. P,h'  a'@al : T) als Ts'"
      by(rule list_all2_mono)(rule addr_loc_type_hext_mono[OF _ h  h'])
    ultimately have "vs h''. heap_copies a a' als h' (concat (map (λ(al, v). [ReadMem a al v, WriteMem a' al v]) (zip als vs))) h''  hconf h''"
      by(rule Cons) }
  then obtain vs h''
    where "heap_copies a a' als h' (concat (map (λ(al, v). [ReadMem a al v, WriteMem a' al v]) (zip als vs))) h''"
    and "hconf h''" by blast
  ultimately
  have "heap_copies a a' (al # als) h ([ReadMem a al v, WriteMem a' al v] @ (concat (map (λ(al, v). [ReadMem a al v, WriteMem a' al v]) (zip als vs)))) h''"
    by- (rule heap_copies.Cons)
  also have "[ReadMem a al v, WriteMem a' al v] @ (concat (map (λ(al, v). [ReadMem a al v, WriteMem a' al v]) (zip als vs))) =
            (concat (map (λ(al, v). [ReadMem a al v, WriteMem a' al v]) (zip (al # als) (v # vs))))" by simp
  finally show ?case using hconf h'' by blast
qed

lemma heap_clone_progress:
  assumes wf: "wf_prog wf_md P"
  and typea: "typeof_addr h a = hT"
  and hconf: "hconf h"
  shows "h' res. heap_clone P h a h' res"
proof -
  from typea hconf have "is_htype P hT" by(rule typeof_addr_is_type)
  show ?thesis
  proof(cases "allocate h hT = {}")
    case True
    with typea CloneFail[of h a hT P]
    show ?thesis by auto
  next
    case False
    then obtain h' a' where new: "(h', a')  allocate h hT" by(rule not_empty_pairE)
    hence "h  h'" by(rule hext_allocate)
    have "hconf h'" using new hconf is_htype P hT by(rule hconf_allocate_mono)
    show ?thesis
    proof(cases hT)
      case [simp]: (Class_type C)
      from is_htype P hT have "is_class P C" by simp
      from wf_Fields_Ex[OF wf this]
      obtain FDTs where FDTs: "P  C has_fields FDTs" ..
      let ?als = "map (λ((F, D), Tfm). CField D F) FDTs"
      let ?Ts = "map (λ(FD, T). fst (the (map_of FDTs FD))) FDTs"
      from typea FDTs have "list_all2 (λal T. P,h  a@al : T) ?als ?Ts"
        unfolding list_all2_map1 list_all2_map2 list_all2_same
        by(fastforce intro: addr_loc_type.intros simp add: has_field_def dest: weak_map_of_SomeI)
      hence "list_all2 (λal T. P,h'  a@al : T) ?als ?Ts"
        by(rule list_all2_mono)(simp add: addr_loc_type_hext_mono[OF _ h  h'] split_def)
      moreover from new is_class P C
      have "typeof_addr h' a' = Class_type C" by(auto dest: allocate_SomeD)
      with FDTs have "list_all2 (λal T. P,h'  a'@al : T) ?als ?Ts"
        unfolding list_all2_map1 list_all2_map2 list_all2_same
        by(fastforce intro: addr_loc_type.intros map_of_SomeI simp add: has_field_def dest: weak_map_of_SomeI)
      ultimately obtain obs h'' where "heap_copies a a' ?als h' obs h''" "hconf h''"
        by(blast dest: heap_copies_progress[OF hconf h'])
      with typea new FDTs ObjClone[of h a C h' a' P FDTs obs h'']
      show ?thesis by auto
    next
      case [simp]: (Array_type T n)
      from wf obtain FDTs where FDTs: "P  Object has_fields FDTs"
        by(blast dest: wf_Fields_Ex is_class_Object)
      let ?als = "map (λ((F, D), Tfm). CField D F) FDTs @ map ACell [0..<n]"
      let ?Ts = "map (λ(FD, T). fst (the (map_of FDTs FD))) FDTs @ replicate n T"
      from h  h' typea have type'a: "typeof_addr h' a = Array_type T n"
        by(auto intro: hext_arrD)
      from type'a FDTs have "list_all2 (λal T. P,h'  a@al : T) ?als ?Ts"
        by(fastforce intro: list_all2_all_nthI addr_loc_type.intros simp add: has_field_def list_all2_append list_all2_map1 list_all2_map2 list_all2_same dest: weak_map_of_SomeI)
      moreover from new is_htype P hT
      have "typeof_addr h' a' = Array_type T n"
        by(auto dest: allocate_SomeD)
      hence "list_all2 (λal T. P,h'  a'@al : T) ?als ?Ts" using FDTs
        by(fastforce intro: list_all2_all_nthI addr_loc_type.intros simp add: has_field_def list_all2_append list_all2_map1 list_all2_map2 list_all2_same dest: weak_map_of_SomeI)
      ultimately obtain obs h'' where "heap_copies a a' ?als h' obs h''" "hconf h''"
        by(blast dest: heap_copies_progress[OF hconf h'])
      with typea new FDTs ArrClone[of h a T n h' a' P FDTs obs h'']
      show ?thesis by auto
    qed
  qed
qed

theorem external_call_progress:
  assumes wf: "wf_prog wf_md P"
  and wt: "P,h  aM(vs) : U"
  and hconf: "hconf h"
  shows "ta va h'. P,t  aM(vs), h -ta→ext va, h'"
proof -
  note [simp del] = split_paired_Ex
  from wt obtain hT Ts Ts' D
    where T: "typeof_addr h a = hT" and Ts: "map typeof⇘hvs = map Some Ts"
    and "P  class_type_of hT sees M:Ts'U = Native in D" and subTs: "P  Ts [≤] Ts'"
    unfolding external_WT'_iff by blast
  from wf P  class_type_of hT sees M:Ts'U = Native in D
  have "DM(Ts') :: U" by(rule sees_wf_native)
  moreover from P  class_type_of hT sees M:Ts'U = Native in D
  have "P  ty_of_htype hT  Class D"
    by(cases hT)(auto dest: sees_method_decl_above intro: widen_trans widen_array_object)
  ultimately show ?thesis using T Ts subTs
  proof cases
    assume [simp]: "D = Object" "M = clone" "Ts' = []" "U = Class Object"
    from heap_clone_progress[OF wf T hconf] obtain h' res where "heap_clone P h a h' res" by blast
    thus ?thesis using subTs Ts by(cases res)(auto intro: red_external.intros)
  qed(auto simp add: widen_Class intro: red_external.intros)
qed

end

subsection ‹Lemmas for preservation of deadlocked threads›

context heap_progress begin

lemma red_external_wt_hconf_hext:
  assumes wf: "wf_prog wf_md P"
  and red: "P,t  aM(vs),h -ta→ext va,h'"
  and hext: "h''  h"
  and wt: "P,h''  aM(vs) : U"
  and tconf: "P,h''  t √t"
  and hconf: "hconf h''"
  shows "ta' va' h'''. P,t  aM(vs),h'' -ta'→ext va', h''' 
                        collect_locks tal = collect_locks ta'l 
                        collect_cond_actions tac = collect_cond_actions ta'c 
                        collect_interrupts tai = collect_interrupts ta'i"
using red wt hext
proof cases
  case (RedClone obs a')
  from wt obtain hT C Ts Ts' D
    where T: "typeof_addr h'' a = hT"
    unfolding external_WT'_iff by blast
  from heap_clone_progress[OF wf T hconf]
  obtain h''' res where "heap_clone P h'' a h''' res" by blast
  thus ?thesis using RedClone
    by(cases res)(fastforce intro: red_external.intros)+
next
  case RedCloneFail
  from wt obtain hT Ts Ts'
    where T: "typeof_addr h'' a = hT"
    unfolding external_WT'_iff by blast
  from heap_clone_progress[OF wf T hconf]
  obtain h''' res where "heap_clone P h'' a h''' res" by blast
  thus ?thesis using RedCloneFail
    by(cases res)(fastforce intro: red_external.intros)+
qed(fastforce simp add: ta_upd_simps elim!: external_WT'.cases intro: red_external.intros[simplified] dest: typeof_addr_hext_mono)+

lemma red_external_wf_red:
  assumes wf: "wf_prog wf_md P"
  and red: "P,t  aM(vs), h -ta→ext va, h'"
  and tconf: "P,h  t √t"
  and hconf: "hconf h"
  and wst: "wset s t = None  (M = wait  (w. wset s t = PostWS w))"
  obtains ta' va' h''
  where "P,t  aM(vs), h -ta'→ext va', h''"
  and "final_thread.actions_ok final s t ta'  final_thread.actions_ok' s t ta'  final_thread.actions_subset ta' ta"
proof(atomize_elim)
  let ?a_t = "thread_id2addr t"
  let ?t_a = "addr2thread_id a"

  from tconf obtain C where ht: "typeof_addr h ?a_t = Class_type C"
    and sub: "P  C * Thread" by(fastforce dest: tconfD)

  show "ta' va' h'. P,t  aM(vs), h -ta'→ext va', h'  (final_thread.actions_ok final s t ta'  final_thread.actions_ok' s t ta'  final_thread.actions_subset ta' ta)"
  proof(cases "final_thread.actions_ok' s t ta")
    case True
    have "final_thread.actions_subset ta ta" by(rule final_thread.actions_subset_refl)
    with True red show ?thesis by blast
  next
    case False
    note [simp] = final_thread.actions_ok'_iff lock_ok_las'_def final_thread.cond_action_oks'_subset_Join
      final_thread.actions_subset_iff ta_upd_simps collect_cond_actions_def collect_interrupts_def
    note [rule del] = subsetI
    note [intro] = collect_locks'_subset_collect_locks red_external.intros[simplified]

    show ?thesis
    proof(cases "wset s t")
      case [simp]: (Some w)
      with wst obtain w' where [simp]: "w = PostWS w'" "M = wait" by auto
      from red have [simp]: "vs = []" by(auto elim: red_external.cases)
      show ?thesis
      proof(cases w')
        case [simp]: WSWokenUp
        let ?ta' = "WokenUp, ClearInterrupt t, ObsInterrupted t"
        have "final_thread.actions_ok' s t ?ta'" by(simp add: wset_actions_ok_def)
        moreover have "final_thread.actions_subset ?ta' ta"
          by(auto simp add: collect_locks'_def finfun_upd_apply)
        moreover from RedWaitInterrupted
        have "va h'. P,t  aM(vs),h -?ta'→ext va,h'" by auto
        ultimately show ?thesis by blast
      next
        case [simp]: WSNotified
        let ?ta' = "Notified"
        have "final_thread.actions_ok' s t ?ta'" by(simp add: wset_actions_ok_def)
        moreover have "final_thread.actions_subset ?ta' ta"
          by(auto simp add: collect_locks'_def finfun_upd_apply)
        moreover from RedWaitNotified
        have "va h'. P,t  aM(vs),h -?ta'→ext va,h'" by auto
        ultimately show ?thesis by blast
      qed
    next
      case None

      from red False show ?thesis
      proof cases
        case (RedNewThread C)
        note ta = ta = NewThread ?t_a (C, run, a) h, ThreadStart ?t_a
        let ?ta' = "ThreadExists ?t_a True"
        from ta False None have "final_thread.actions_ok' s t ?ta'" by(auto)
        moreover from ta have "final_thread.actions_subset ?ta' ta" by(auto)
        ultimately show ?thesis using RedNewThread by(fastforce)
      next
        case RedNewThreadFail
        then obtain va' h' x where "P,t  aM(vs), h -NewThread ?t_a x h', ThreadStart ?t_a→ext va', h'"
          by(fastforce)
        moreover from ta = ThreadExists ?t_a True False None
        have "final_thread.actions_ok' s t NewThread ?t_a x h', ThreadStart ?t_a" by(auto)
        moreover from ta = ThreadExists ?t_a True
        have "final_thread.actions_subset NewThread ?t_a x h', ThreadStart ?t_a ta" by(auto)
        ultimately show ?thesis by blast
      next
        case RedJoin
        let ?ta = "IsInterrupted t True, ClearInterrupt t, ObsInterrupted t"
        from ta = Join (addr2thread_id a), IsInterrupted t False, ThreadJoin (addr2thread_id a) None False
        have "t  interrupts s" by(auto)
        hence "final_thread.actions_ok final s t ?ta"
          using None by(auto simp add: final_thread.actions_ok_iff final_thread.cond_action_oks.simps)
        moreover obtain va h' where "P,t  aM(vs),h -?ta→ext va,h'" using RedJoinInterrupt RedJoin by auto
        ultimately show ?thesis by blast
      next
        case RedJoinInterrupt
        hence False using False None by(auto)
        thus ?thesis ..
      next
        case RedInterrupt
        let ?ta = "ThreadExists (addr2thread_id a) False"
        from RedInterrupt None False
        have "free_thread_id (thr s) (addr2thread_id a)" by(auto simp add: wset_actions_ok_def)
        hence "final_thread.actions_ok final s t ?ta" using None
          by(auto simp add: final_thread.actions_ok_iff final_thread.cond_action_oks.simps)
        moreover obtain va h' where "P,t  aM(vs),h -?ta→ext va,h'" using RedInterruptInexist RedInterrupt by auto
        ultimately show ?thesis by blast
      next
        case RedInterruptInexist
        let ?ta = "ThreadExists (addr2thread_id a) True, WakeUp (addr2thread_id a), Interrupt (addr2thread_id a), ObsInterrupt (addr2thread_id a)"
        from RedInterruptInexist None False
        have "¬ free_thread_id (thr s) (addr2thread_id a)" by(auto simp add: wset_actions_ok_def)
        hence "final_thread.actions_ok final s t ?ta" using None
          by(auto simp add: final_thread.actions_ok_iff final_thread.cond_action_oks.simps wset_actions_ok_def)
        moreover obtain va h' where "P,t  aM(vs),h -?ta→ext va,h'" using RedInterruptInexist RedInterrupt by auto
        ultimately show ?thesis by blast
      next
        case (RedIsInterruptedTrue C)
        let ?ta' = "IsInterrupted ?t_a False"
        from RedIsInterruptedTrue False None have "?t_a  interrupts s" by(auto)
        hence "final_thread.actions_ok' s t ?ta'" using None by auto
        moreover from RedIsInterruptedTrue have "final_thread.actions_subset ?ta' ta" by auto
        moreover from RedIsInterruptedTrue RedIsInterruptedFalse obtain va h'
          where "P,t  aM(vs),h -?ta'→ext va,h'" by auto
        ultimately show ?thesis by blast
      next
        case (RedIsInterruptedFalse C)
        let ?ta' = "IsInterrupted ?t_a True, ObsInterrupted ?t_a"
        from RedIsInterruptedFalse have "?t_a  interrupts s"
          using False None by(auto)
        hence "final_thread.actions_ok final s t ?ta'"
          using None by(auto simp add: final_thread.actions_ok_iff final_thread.cond_action_oks.simps)
        moreover obtain va h' where "P,t  aM(vs),h -?ta'→ext va,h'"
          using RedIsInterruptedFalse RedIsInterruptedTrue by auto
        ultimately show ?thesis by blast
      next
        case RedWaitInterrupt
        note ta = ta = Unlocka, Locka, IsInterrupted t True, ClearInterrupt t, ObsInterrupted t
        from ta False None have hli: "¬ has_lock (locks s $ a) t  t  interrupts s"
          by(fastforce simp add: lock_actions_ok'_iff finfun_upd_apply split: if_split_asm dest: may_lock_t_may_lock_unlock_lock_t dest: has_lock_may_lock)
        show ?thesis
        proof(cases "has_lock (locks s $ a) t")
          case True
          let ?ta' = "Suspend a, Unlocka, Locka, ReleaseAcquirea, IsInterrupted t False, SyncUnlock a "
          from True hli have "t  interrupts s" by simp
          with True False have "final_thread.actions_ok' s t ?ta'" using None
            by(auto simp add: lock_actions_ok'_iff finfun_upd_apply wset_actions_ok_def Cons_eq_append_conv)
          moreover from ta have "final_thread.actions_subset ?ta' ta"
            by(auto simp add: collect_locks'_def finfun_upd_apply)
          moreover from RedWait RedWaitInterrupt obtain va h' where "P,t  aM(vs),h -?ta'→ext va,h'" by auto
          ultimately show ?thesis by blast
        next
          case False
          let ?ta' = "UnlockFaila"
          from False have "final_thread.actions_ok' s t ?ta'" using None
            by(auto simp add: lock_actions_ok'_iff finfun_upd_apply)
          moreover from ta have "final_thread.actions_subset ?ta' ta"
            by(auto simp add: collect_locks'_def finfun_upd_apply)
          moreover from RedWaitInterrupt obtain va h' where "P,t  aM(vs),h -?ta'→ext va,h'" by(fastforce)
          ultimately show ?thesis by blast
        qed
      next
        case RedWait
        note ta = ta = Suspend a, Unlocka, Locka, ReleaseAcquirea, IsInterrupted t False, SyncUnlock a

        from ta False None have hli: "¬ has_lock (locks s $ a) t  t  interrupts s"
          by(auto simp add: lock_actions_ok'_iff finfun_upd_apply wset_actions_ok_def Cons_eq_append_conv split: if_split_asm dest: may_lock_t_may_lock_unlock_lock_t dest: has_lock_may_lock)
        show ?thesis
        proof(cases "has_lock (locks s $ a) t")
          case True
          let ?ta' = "Unlocka, Locka, IsInterrupted t True, ClearInterrupt t, ObsInterrupted t"
          from True hli have "t  interrupts s" by simp
          with True False have "final_thread.actions_ok final s t ?ta'" using None
            by(auto simp add: final_thread.actions_ok_iff final_thread.cond_action_oks.simps lock_ok_las_def finfun_upd_apply has_lock_may_lock)
          moreover from RedWait RedWaitInterrupt obtain va h' where "P,t  aM(vs),h -?ta'→ext va,h'" by auto
          ultimately show ?thesis by blast
        next
          case False
          let ?ta' = "UnlockFaila"
          from False have "final_thread.actions_ok' s t ?ta'" using None
            by(auto simp add: lock_actions_ok'_iff finfun_upd_apply)
          moreover from ta have "final_thread.actions_subset ?ta' ta"
            by(auto simp add: collect_locks'_def finfun_upd_apply)
          moreover from RedWait RedWaitFail obtain va h' where "P,t  aM(vs),h -?ta'→ext va,h'" by(fastforce)
          ultimately show ?thesis by blast
        qed
      next
        case RedWaitFail
        note ta = ta = UnlockFaila
        let ?ta' = "if t  interrupts s
                   then Unlocka, Locka, IsInterrupted t True, ClearInterrupt t, ObsInterrupted t
                   else Suspend a, Unlocka, Locka, ReleaseAcquirea, IsInterrupted t False, SyncUnlock a "
        from ta False None have "has_lock (locks s $ a) t"
          by(auto simp add: finfun_upd_apply split: if_split_asm)
        hence "final_thread.actions_ok final s t ?ta'" using None
          by(auto simp add: final_thread.actions_ok_iff final_thread.cond_action_oks.simps lock_ok_las_def finfun_upd_apply has_lock_may_lock wset_actions_ok_def)
        moreover from RedWaitFail RedWait RedWaitInterrupt
        obtain va h' where "P,t  aM(vs),h -?ta'→ext va,h'"
          by(cases "t  interrupts s") (auto)
        ultimately show ?thesis by blast
      next
        case RedWaitNotified
        note ta = ta = Notified
        let ?ta' = "if has_lock (locks s $ a) t
                   then (if t  interrupts s
                         then Unlocka, Locka, IsInterrupted t True, ClearInterrupt t, ObsInterrupted t
                         else Suspend a, Unlocka, Locka, ReleaseAcquirea, IsInterrupted t False, SyncUnlock a )
                   else UnlockFaila"
        have "final_thread.actions_ok final s t ?ta'" using None
          by(auto simp add: final_thread.actions_ok_iff final_thread.cond_action_oks.simps lock_ok_las_def finfun_upd_apply has_lock_may_lock wset_actions_ok_def)
        moreover from RedWaitNotified RedWait RedWaitInterrupt RedWaitFail
        have "va h'. P,t  aM(vs),h -?ta'→ext va,h'" by auto
        ultimately show ?thesis by blast
      next
        case RedWaitInterrupted
        note ta = ta = WokenUp, ClearInterrupt t, ObsInterrupted t
        let ?ta' = "if has_lock (locks s $ a) t
                   then (if t  interrupts s
                         then Unlocka, Locka, IsInterrupted t True, ClearInterrupt t, ObsInterrupted t
                         else Suspend a, Unlocka, Locka, ReleaseAcquirea, IsInterrupted t False, SyncUnlock a )
                   else UnlockFaila"
        have "final_thread.actions_ok final s t ?ta'" using None
          by(auto simp add: final_thread.actions_ok_iff final_thread.cond_action_oks.simps lock_ok_las_def finfun_upd_apply has_lock_may_lock wset_actions_ok_def)
        moreover from RedWaitInterrupted RedWait RedWaitInterrupt RedWaitFail
        have "va h'. P,t  aM(vs),h -?ta'→ext va,h'" by auto
        ultimately show ?thesis by blast
      next
        case RedWaitSpurious
        note ta = ta = Unlocka, Locka, ReleaseAcquirea, IsInterrupted t False, SyncUnlock a
        from ta False None have hli: "¬ has_lock (locks s $ a) t  t  interrupts s"
          by(auto simp add: lock_actions_ok'_iff finfun_upd_apply wset_actions_ok_def Cons_eq_append_conv split: if_split_asm dest: may_lock_t_may_lock_unlock_lock_t dest: has_lock_may_lock)
        show ?thesis
        proof(cases "has_lock (locks s $ a) t")
          case True
          let ?ta' = "Unlocka, Locka, IsInterrupted t True, ClearInterrupt t, ObsInterrupted t"
          from True hli have "t  interrupts s" by simp
          with True False have "final_thread.actions_ok final s t ?ta'" using None
            by(auto simp add: final_thread.actions_ok_iff final_thread.cond_action_oks.simps lock_ok_las_def finfun_upd_apply has_lock_may_lock)
          moreover from RedWaitInterrupt RedWaitSpurious(1-5)
          obtain va h' where "P,t  aM(vs),h -?ta'→ext va,h'" by auto
          ultimately show ?thesis by blast
        next
          case False
          let ?ta' = "UnlockFaila"
          from False have "final_thread.actions_ok' s t ?ta'" using None
            by(auto simp add: lock_actions_ok'_iff finfun_upd_apply)
          moreover from ta have "final_thread.actions_subset ?ta' ta"
            by(auto simp add: collect_locks'_def finfun_upd_apply)
          moreover from RedWaitSpurious(1-5) RedWaitFail
          obtain va h' where "P,t  aM(vs),h -?ta'→ext va,h'" by(fastforce)
          ultimately show ?thesis by blast
        qed

      next
        case RedNotify
        note ta = ta = Notify a, Unlocka, Locka
        let ?ta' = "UnlockFaila"
        from ta False None have "¬ has_lock (locks s $ a) t"
          by(fastforce simp add: lock_actions_ok'_iff finfun_upd_apply wset_actions_ok_def Cons_eq_append_conv split: if_split_asm dest: may_lock_t_may_lock_unlock_lock_t has_lock_may_lock)
        hence "final_thread.actions_ok' s t ?ta'" using None
          by(auto simp add: lock_actions_ok'_iff finfun_upd_apply)
        moreover from ta have "final_thread.actions_subset ?ta' ta"
          by(auto simp add: collect_locks'_def finfun_upd_apply)
        moreover from RedNotify obtain va h' where "P,t  aM(vs),h -?ta'→ext va,h'" by(fastforce)
        ultimately show ?thesis by blast
      next
        case RedNotifyFail
        note ta = ta = UnlockFaila
        let ?ta' = "Notify a, Unlocka, Locka"
        from ta False None have "has_lock (locks s $ a) t"
          by(auto simp add: finfun_upd_apply split: if_split_asm)
        hence "final_thread.actions_ok' s t ?ta'" using None
          by(auto simp add: finfun_upd_apply simp add: wset_actions_ok_def intro: has_lock_may_lock)
        moreover from ta have "final_thread.actions_subset ?ta' ta"
          by(auto simp add: collect_locks'_def finfun_upd_apply)
        moreover from RedNotifyFail obtain va h' where "P,t  aM(vs),h -?ta'→ext va,h'" by(fastforce)
        ultimately show ?thesis by blast
      next
        case RedNotifyAll
        note ta = ta = NotifyAll a, Unlocka, Locka
        let ?ta' = "UnlockFaila"
        from ta False None have "¬ has_lock (locks s $ a) t"
          by(auto simp add: lock_actions_ok'_iff finfun_upd_apply wset_actions_ok_def Cons_eq_append_conv split: if_split_asm dest: may_lock_t_may_lock_unlock_lock_t)
        hence "final_thread.actions_ok' s t ?ta'" using None
          by(auto simp add: lock_actions_ok'_iff finfun_upd_apply)
        moreover from ta have "final_thread.actions_subset ?ta' ta"
          by(auto simp add: collect_locks'_def finfun_upd_apply)
        moreover from RedNotifyAll obtain va h' where "P,t  aM(vs),h -?ta'→ext va,h'" by(fastforce)
        ultimately show ?thesis by blast
      next
        case RedNotifyAllFail
        note ta = ta = UnlockFaila
        let ?ta' = "NotifyAll a, Unlocka, Locka"
        from ta False None have "has_lock (locks s $ a) t"
          by(auto simp add: finfun_upd_apply split: if_split_asm)
        hence "final_thread.actions_ok' s t ?ta'" using None
          by(auto simp add: finfun_upd_apply wset_actions_ok_def intro: has_lock_may_lock)
        moreover from ta have "final_thread.actions_subset ?ta' ta"
          by(auto simp add: collect_locks'_def finfun_upd_apply)
        moreover from RedNotifyAllFail obtain va h' where "P,t  aM(vs),h -?ta'→ext va,h'" by(fastforce)
        ultimately show ?thesis by blast
      next
        case RedInterruptedTrue
        let ?ta' = "IsInterrupted t False"
        from RedInterruptedTrue have "final_thread.actions_ok final s t ?ta'"
          using None False by(auto simp add: final_thread.actions_ok_iff final_thread.cond_action_oks.simps)
        moreover obtain va h' where "P,t  aM(vs),h -?ta'→ext va,h'"
          using RedInterruptedFalse RedInterruptedTrue by auto
        ultimately show ?thesis by blast
      next
        case RedInterruptedFalse
        let ?ta' = "IsInterrupted t True, ClearInterrupt t, ObsInterrupted t"
        from RedInterruptedFalse have "final_thread.actions_ok final s t ?ta'"
          using None False
          by(auto simp add: final_thread.actions_ok_iff final_thread.cond_action_oks.simps)
        moreover obtain va h' where "P,t  aM(vs),h -?ta'→ext va,h'"
          using RedInterruptedFalse RedInterruptedTrue by auto
        ultimately show ?thesis by blast
      qed(auto simp add: None)
    qed
  qed
qed

end

context heap_base begin

lemma red_external_ta_satisfiable:
  fixes final
  assumes "P,t  aM(vs), h -ta→ext va, h'"
  shows "s. final_thread.actions_ok final s t ta"
proof -
  note [simp] =
    final_thread.actions_ok_iff final_thread.cond_action_oks.simps final_thread.cond_action_ok.simps
    lock_ok_las_def finfun_upd_apply wset_actions_ok_def has_lock_may_lock
    and [intro] =
    free_thread_id.intros
    and [cong] = conj_cong

  from assms show ?thesis by cases(fastforce intro: exI[where x="(K$ None)(a $:= (t, 0))"] exI[where x="(K$ None)"])+
qed

lemma red_external_aggr_ta_satisfiable:
  fixes final
  assumes "(ta, va, h')  red_external_aggr P t a M vs h"
  shows "s. final_thread.actions_ok final s t ta"
proof -
  note [simp] =
    final_thread.actions_ok_iff final_thread.cond_action_oks.simps final_thread.cond_action_ok.simps
    lock_ok_las_def finfun_upd_apply wset_actions_ok_def has_lock_may_lock
    and [intro] =
    free_thread_id.intros
    and [cong] = conj_cong

  from assms show ?thesis
    by(fastforce simp add: red_external_aggr_def split_beta ta_upd_simps split: if_split_asm intro: exI[where x="Map.empty"] exI[where x="(K$ None)(a $:= (t, 0))"] exI[where x="K$ None"])
qed

end

subsection ‹Determinism›

context heap_base begin

lemma heap_copy_loc_deterministic:
  assumes det: "deterministic_heap_ops"
  and copy: "heap_copy_loc a a' al h ops h'" "heap_copy_loc a a' al h ops' h''"
  shows "ops = ops'  h' = h''"
using copy
by(auto elim!: heap_copy_loc.cases dest: deterministic_heap_ops_readD[OF det] deterministic_heap_ops_writeD[OF det])

lemma heap_copies_deterministic:
  assumes det: "deterministic_heap_ops"
  and copy: "heap_copies a a' als h ops h'" "heap_copies a a' als h ops' h''"
  shows "ops = ops'  h' = h''"
using copy
apply(induct arbitrary: ops' h'')
 apply(fastforce elim!: heap_copies_cases)
apply(erule heap_copies_cases)
apply clarify
apply(drule (1) heap_copy_loc_deterministic[OF det])
apply clarify
apply(unfold same_append_eq)
apply blast
done

lemma heap_clone_deterministic:
  assumes det: "deterministic_heap_ops"
  and clone: "heap_clone P h a h' obs" "heap_clone P h a h'' obs'"
  shows "h' = h''  obs = obs'"
using clone
by(auto 4 4 elim!: heap_clone.cases dest: heap_copies_deterministic[OF det] deterministic_heap_ops_allocateD[OF det] has_fields_fun)

lemma red_external_deterministic:
  fixes final
  assumes det: "deterministic_heap_ops"
  and red: "P,t  aM(vs), (shr s) -ta→ext va, h'" "P,t  aM(vs), (shr s) -ta'→ext va', h''"
  and aok: "final_thread.actions_ok final s t ta" "final_thread.actions_ok final s t ta'"
  shows "ta = ta'  va = va'  h' = h''"
using red aok
apply(simp add: final_thread.actions_ok_iff lock_ok_las_def)
apply(erule red_external.cases)
apply(erule_tac [!] red_external.cases)
apply simp_all
apply(auto simp add: finfun_upd_apply wset_actions_ok_def dest: heap_clone_deterministic[OF det] split: if_split_asm)
using deterministic_heap_ops_no_spurious_wakeups[OF det]
apply simp_all
done

end

end