Theory FWLock

(*  Title:      JinjaThreads/Framework/FWLock.thy
    Author:     Andreas Lochbihler
*)

section ‹All about a managing a single lock›

theory FWLock
imports
  FWState
begin

fun has_locks :: "'t lock  't  nat" where
  "has_locks None t = 0"
| "has_locks (t', n) t = (if t = t' then Suc n else 0)"

lemma has_locks_iff: 
  "has_locks l t = n 
  (l = None  n = 0)  
  (n'. l = (t, n')  Suc n' = n)  (t' n'. l = (t', n')  t'  t  n = 0)"
by(cases l, auto)

lemma has_locksE:
  " has_locks l t = n;
      l = None; n = 0   P;
     n'.  l = (t, n'); Suc n' = n   P;
     t' n'.  l = (t', n'); t'  t; n = 0   P 
   P"
by(auto simp add: has_locks_iff split: if_split_asm prod.split_asm)


inductive may_lock :: "'t lock  't  bool" where
  "may_lock None t"
| "may_lock (t, n) t"

lemma may_lock_iff [code]:
  "may_lock l t = (case l of None  True | (t', n)  t = t')"
by(auto intro: may_lock.intros elim: may_lock.cases)

lemma may_lockI:
  "l = None  (n. l = (t, n))  may_lock l t"
by(cases l, auto intro: may_lock.intros)

lemma may_lockE [consumes 1, case_names None Locked]:
  " may_lock l t; l = None  P; n. l = (t, n)   P   P"
by(auto elim: may_lock.cases)

lemma may_lock_may_lock_t_eq:
  " may_lock l t; may_lock l t'   (l = None)  (t = t')"
by(auto elim!: may_lockE)

abbreviation has_lock :: "'t lock  't  bool"
where "has_lock l t  0 < has_locks l t"

lemma has_locks_Suc_has_lock:
  "has_locks l t = Suc n  has_lock l t"
by(auto)

lemmas has_lock_has_locks_Suc = gr0_implies_Suc[where n = "has_locks l t"] for l t

lemma has_lock_has_locks_conv:
  "has_lock l t  (n. has_locks l t = (Suc n))"
by(auto intro: has_locks_Suc_has_lock has_lock_has_locks_Suc)

lemma has_lock_may_lock:
  "has_lock l t  may_lock l t"
by(cases l, auto intro: may_lockI)

lemma has_lock_may_lock_t_eq:
  " has_lock l t; may_lock l t'   t = t'"
by(auto elim!: may_lockE split: if_split_asm)

lemma has_locks_has_locks_t_eq: 
  "has_locks l t = Suc n; has_locks l t' = Suc n'  t = t'"
by(auto elim: has_locksE)

lemma has_lock_has_lock_t_eq:
  " has_lock l t; has_lock l t'   t = t'"
unfolding has_lock_has_locks_conv
by(auto intro: has_locks_has_locks_t_eq)

lemma not_may_lock_conv:
  "¬ may_lock l t  (t'. t'  t  has_lock l t')"
by(cases l, auto intro: may_lock.intros elim: may_lockE)



(* State update functions for locking *)

fun lock_lock :: "'t lock  't  't lock" where
  "lock_lock None t = (t, 0)"
| "lock_lock (t', n) t = (t', Suc n)"

fun unlock_lock :: "'t lock  't lock" where
  "unlock_lock None = None"
| "unlock_lock (t, n) = (case n of 0  None | Suc n'  (t, n'))"

fun release_all :: "'t lock  't  't lock" where
  "release_all None t = None"
| "release_all (t', n) t = (if t = t' then None else (t', n))"

fun acquire_locks :: "'t lock  't  nat  't lock" where
  "acquire_locks L t 0 = L"
| "acquire_locks L t (Suc m) = acquire_locks (lock_lock L t) t m"

lemma acquire_locks_conv:
  "acquire_locks L t n = (case L of None  (case n of 0  None | Suc m  (t, m)) | (t', m)  (t', n + m))"
by(induct n arbitrary: L)(auto)

lemma lock_lock_ls_Some:
  "t' n. lock_lock l t = (t', n)"
by(cases l, auto)

lemma unlock_lock_SomeD:
  "unlock_lock l = (t', n)  l = (t', Suc n)"
by(cases l, auto split: nat.split_asm)

lemma has_locks_Suc_lock_lock_has_locks_Suc_Suc:
  "has_locks l t = Suc n  has_locks (lock_lock l t) t = Suc (Suc n)"
by(auto elim!: has_locksE)

lemma has_locks_lock_lock_conv [simp]:
  "may_lock l t  has_locks (lock_lock l t) t = Suc (has_locks l t)"
by(auto elim: may_lockE)

lemma has_locks_release_all_conv [simp]:
  "has_locks (release_all l t) t = 0"
by(cases l, auto split: if_split_asm)

lemma may_lock_lock_lock_conv [simp]: "may_lock (lock_lock l t) t = may_lock l t"
by(cases l, auto elim!: may_lock.cases intro: may_lock.intros)

lemma has_locks_acquire_locks_conv [simp]:
  "may_lock l t  has_locks (acquire_locks l t n) t = has_locks l t + n"
by(induct n arbitrary: l, auto)

lemma may_lock_unlock_lock_conv [simp]:
  "has_lock l t  may_lock (unlock_lock l) t = may_lock l t"
by(cases l)(auto split: if_split_asm nat.splits elim!: may_lock.cases intro: may_lock.intros)

lemma may_lock_release_all_conv [simp]:
  "may_lock (release_all l t) t = may_lock l t"
by(cases l, auto split: if_split_asm intro!: may_lockI elim: may_lockE)

lemma may_lock_t_may_lock_unlock_lock_t: 
  "may_lock l t  may_lock (unlock_lock l) t"
by(auto intro: may_lock.intros elim!: may_lockE split: nat.split)


lemma may_lock_has_locks_lock_lock_0: 
  "may_lock l t'; t  t'  has_locks (lock_lock l t') t = 0"
by(auto elim!: may_lock.cases)

lemma has_locks_unlock_lock_conv [simp]:
  "has_lock l t  has_locks (unlock_lock l) t = has_locks l t - 1"
by(cases l)(auto split: nat.split)

lemma has_lock_lock_lock_unlock_lock_id [simp]:
  "has_lock l t  lock_lock (unlock_lock l) t = l"
by(cases l)(auto split: if_split_asm nat.split)

lemma may_lock_unlock_lock_lock_lock_id [simp]:
  "may_lock l t  unlock_lock (lock_lock l t) = l"
by(cases l) auto


lemma may_lock_has_locks_0:
  " may_lock l t; t  t'   has_locks l t' = 0"
by(auto elim!: may_lockE)


fun upd_lock :: "'t lock  't  lock_action  't lock"
where
  "upd_lock l t Lock = lock_lock l t"
| "upd_lock l t Unlock = unlock_lock l"
| "upd_lock l t UnlockFail = l"
| "upd_lock l t ReleaseAquire = release_all l t"

fun upd_locks :: "'t lock  't  lock_action list  't lock"
where
  "upd_locks l t [] = l"
| "upd_locks l t (L # Ls) = upd_locks (upd_lock l t L) t Ls"

lemma upd_locks_append [simp]:
  "upd_locks l t (Ls @ Ls') = upd_locks (upd_locks l t Ls) t Ls'"
by(induct Ls arbitrary: l, auto)

lemma upd_lock_Some_thread_idD:
  assumes ul: "upd_lock l t L = (t', n)"
  and tt': "t  t'"
  shows "n. l = (t', n)"
proof(cases L)
  case Lock
  with ul tt' show ?thesis
    by(cases l, auto)
next
  case Unlock
  with ul tt' show ?thesis
    by(auto dest: unlock_lock_SomeD)
next
  case UnlockFail
  with ul show ?thesis by(simp)
next
  case ReleaseAcquire
  with ul show ?thesis
    by(cases l, auto split: if_split_asm)
qed


lemma has_lock_upd_lock_implies_has_lock:
  " has_lock (upd_lock l t L) t'; t  t'   has_lock l t'"
by(cases l L rule: option.exhaust[case_product lock_action.exhaust])(auto split: if_split_asm nat.split_asm)

lemma has_lock_upd_locks_implies_has_lock:
  " has_lock (upd_locks l t Ls) t'; t  t'   has_lock l t'"
by(induct l t Ls rule: upd_locks.induct)(auto intro: has_lock_upd_lock_implies_has_lock)

(* Preconditions for lock actions *)

fun lock_action_ok :: "'t lock  't  lock_action  bool" where
  "lock_action_ok l t Lock = may_lock l t"
| "lock_action_ok l t Unlock = has_lock l t"
| "lock_action_ok l t UnlockFail = (¬ has_lock l t)"
| "lock_action_ok l t ReleaseAcquire = True"

fun lock_actions_ok :: "'t lock  't  lock_action list  bool" where
  "lock_actions_ok l t [] = True"
| "lock_actions_ok l t (L # Ls) = (lock_action_ok l t L  lock_actions_ok (upd_lock l t L) t Ls)"

lemma lock_actions_ok_append [simp]:
  "lock_actions_ok l t (Ls @ Ls')  lock_actions_ok l t Ls  lock_actions_ok (upd_locks l t Ls) t Ls'"
by(induct Ls arbitrary: l) auto

lemma not_lock_action_okE [consumes 1, case_names Lock Unlock UnlockFail]:
  " ¬ lock_action_ok l t L;
      L = Lock; ¬ may_lock l t   Q;
      L = Unlock; ¬ has_lock l t   Q;
      L = UnlockFail; has_lock l t   Q
   Q"
by(cases L) auto

lemma may_lock_upd_lock_conv [simp]:
  "lock_action_ok l t L  may_lock (upd_lock l t L) t = may_lock l t"
by(cases L) auto

lemma may_lock_upd_locks_conv [simp]:
  "lock_actions_ok l t Ls  may_lock (upd_locks l t Ls) t = may_lock l t"
by(induct l t Ls rule: upd_locks.induct) simp_all

lemma lock_actions_ok_Lock_may_lock:
  " lock_actions_ok l t Ls; Lock  set Ls   may_lock l t"
by(induct l t Ls rule: lock_actions_ok.induct) auto

lemma has_locks_lock_lock_conv' [simp]:
  " may_lock l t'; t  t'   has_locks (lock_lock l t') t = has_locks l t"
by(cases l)(auto elim: may_lock.cases)

lemma has_locks_unlock_lock_conv' [simp]:
  " has_lock l t'; t  t'   has_locks (unlock_lock l) t = has_locks l t"
by(cases l)(auto split: if_split_asm nat.split)

lemma has_locks_release_all_conv' [simp]:
  "t  t'  has_locks (release_all l t') t = has_locks l t"
by(cases l) auto

lemma has_locks_acquire_locks_conv' [simp]:
  " may_lock l t; t  t'   has_locks (acquire_locks l t n) t' = has_locks l t'"
by(induct l t n rule: acquire_locks.induct) simp_all

lemma lock_action_ok_has_locks_upd_lock_eq_has_locks [simp]:
  " lock_action_ok l t' L; t  t'   has_locks (upd_lock l t' L) t = has_locks l t"
by(cases L) auto

lemma lock_actions_ok_has_locks_upd_locks_eq_has_locks [simp]:
  " lock_actions_ok l t' Ls; t  t'   has_locks (upd_locks l t' Ls) t = has_locks l t"
by(induct l t' Ls rule: upd_locks.induct) simp_all

lemma has_lock_acquire_locks_implies_has_lock:
  " has_lock (acquire_locks l t n) t'; t  t'   has_lock l t'"
 unfolding acquire_locks_conv
 by(cases n)(auto split: if_split_asm)

lemma has_lock_has_lock_acquire_locks:
  "has_lock l T  has_lock (acquire_locks l t n) T"
  unfolding acquire_locks_conv
  by(auto)


fun lock_actions_ok' :: "'t lock  't  lock_action list  bool" where
  "lock_actions_ok' l t [] = True"
| "lock_actions_ok' l t (L#Ls) = ((L = Lock  ¬ may_lock l t) 
                                  lock_action_ok l t L  lock_actions_ok' (upd_lock l t L) t Ls)"

lemma lock_actions_ok'_iff:
  "lock_actions_ok' l t las  
   lock_actions_ok l t las  (xs ys. las = xs @ Lock # ys  lock_actions_ok l t xs  ¬ may_lock (upd_locks l t xs) t)"
proof(induct l t las rule: lock_actions_ok.induct)
  case (2 L t LA LAS)
  show ?case
  proof(cases "LA = Lock  ¬ may_lock L t")
    case True
    hence "(ys. Lock # LAS = [] @ Lock # ys)  lock_actions_ok L t []  ¬ may_lock (upd_locks L t []) t"
      by(simp)
    with True show ?thesis by(simp (no_asm))(blast)
  next
    case False
    with 2 show ?thesis
      by(fastforce simp add: Cons_eq_append_conv elim: allE[where x="LA # xs" for xs])
  qed
qed simp

lemma lock_actions_ok'E[consumes 1, case_names ok Lock]:
  " lock_actions_ok' l t las;
     lock_actions_ok l t las  P;
     xs ys.  las = xs @ Lock # ys; lock_actions_ok l t xs; ¬ may_lock (upd_locks l t xs) t   P  
   P"
by(auto simp add: lock_actions_ok'_iff)

end