Definition blocked_at_external (state : cm_state) (ef : external_function) :=
match state with
(m, (tr, sch, tp)) =>
exists j cntj sch' c args,
sch = j :: sch' /\
@getThreadC _ _ _ j tp cntj = Kblocked c /\
cl_at_external c = Some (ef, args)
end.
Definition state_bupd P (state : cm_state) := let '(m, (tr, sch, tp)) := state in
tp_bupd (fun tp' => P (m, (tr, sch, tp'))) tp.

(* Specifications: *)
Lemma state_bupd_intro : forall (P : _ -> Prop) m tr sch tp phi, join_all tp phi ->
joins (ghost_of phi) (Some (ext_ref tt, NoneP) :: nil) ->
P (m, (tr, sch, tp)) -> state_bupd P (m, (tr, sch, tp)).
Lemma state_bupd_intro' : forall Gamma n s,
state_invariant Gamma n s ->
state_bupd (state_invariant Gamma n) s.
Lemma mem_compatible_upd : forall tp m phi tp' phi', mem_compatible_with tp m phi ->
tp_update(ge := ge) tp phi tp' phi' -> mem_compatible_with tp' m phi'.
Lemma join_all_eq : forall (tp : jstate ge) phi phi', join_all tp phi -> join_all tp phi' ->
(getThreadsR tp = nil /\ getLocksR tp = nil /\ identity phi /\ identity phi') \/ phi = phi'.
(* Ghost update only affects safety; the rest of the invariant is preserved. *)
Lemma state_inv_upd : forall Gamma (n : nat)
(m : mem) (tr : event_trace) (sch : schedule) (tp : jstate ge) (PHI : rmap)
(lev : level PHI = n)
(envcoh : env_coherence Jspec ge Gamma PHI)
(mcompat : mem_compatible_with tp m PHI)
(extcompat : joins (ghost_of PHI) (Some (ext_ref tt, NoneP) :: nil))
(lock_sparse : lock_sparsity (lset tp))
(lock_coh : lock_coherence' tp PHI m mcompat)
(safety : forall C, join_sub (Some (ext_ref tt, NoneP) :: nil) C ->
joins (ghost_of PHI) (ghost_fmap (approx (level PHI)) (approx (level PHI)) C) ->
exists tp' PHI' (Hupd : tp_update tp PHI tp' PHI'),
joins (ghost_of PHI') (ghost_fmap (approx (level PHI)) (approx (level PHI)) C) /\
threads_safety m tp' PHI' (mem_compatible_upd _ _ _ _ _ mcompat Hupd) n)
(wellformed : threads_wellformed tp)
(uniqkrun :  unique_Krun tp sch),
state_bupd (state_invariant Gamma n) (m, (tr, sch, tp)).