Section LockServ.
Variable num_Clients : nat.
Definition Client_index := (fin num_Clients).
Inductive Name :=
| Client : Client_index -> Name
| Server : Name.
Definition list_Clients := map Client (all_fin num_Clients).
Definition Name_eq_dec : forall a b : Name, {a = b} + {a <> b}.
decide equality. apply fin_eq_dec.
Qed.
Inductive Msg :=
| Lock   : Msg
| Unlock : Msg
| Locked : Msg.
Definition Msg_eq_dec : forall a b : Msg, {a = b} + {a <> b}.
decide equality.
Qed.
Definition Input := Msg.
Definition Output := Msg.
Record Data := mkData { queue : list Client_index ; held : bool }.
Definition init_data (n : Name) : Data := mkData [] false.
Definition Handler (S : Type) := GenHandler (Name * Msg) S Output unit.
Definition ClientNetHandler (i : Client_index) (m : Msg) : Handler Data :=
match m with
| Locked => (put (mkData [] true)) >> write_output Locked
| _ => nop
end.
Definition ClientIOHandler (i : Client_index) (m : Msg) : Handler Data :=
match m with
| Lock => send (Server, Lock)
| Unlock => data <- get ;;
when (held data) (put (mkData [] false) >> send (Server, Unlock))
| _ => nop
end.
Definition ServerNetHandler (src : Name) (m : Msg) : Handler Data :=
st <- get ;;
let q := queue st in
match m with
| Lock =>
match src with
| Server => nop
| Client c =>
when (null q) (send (src, Locked)) >> put (mkData (q++[c]) (held st))
end
| Unlock => match q with
| _ :: x :: xs => put (mkData (x :: xs) (held st)) >> send (Client x, Locked)
| _ => put (mkData [] (held st))
end
| _ => nop
end.
Definition ServerIOHandler (m : Msg) : Handler Data := nop.
Definition NetHandler (nm src : Name) (m : Msg) : Handler Data :=
match nm with
| Client c => ClientNetHandler c m
| Server   => ServerNetHandler src m
end.
Definition InputHandler (nm : Name) (m : Msg) : Handler Data :=
match nm with
| Client c => ClientIOHandler c m
| Server   => ServerIOHandler m
end.
Ltac handler_unfold :=
repeat (monad_unfold; unfold NetHandler,
InputHandler,
ServerNetHandler,
ClientNetHandler,
ClientIOHandler,
ServerIOHandler in *).
Definition Nodes := Server :: list_Clients.
Proof using.
intros.
unfold Nodes, list_Clients.
simpl.
destruct n.
- right.
apply in_map.
apply all_fin_all.
- left.
reflexivity.
Qed.
Proof using.
unfold Nodes, list_Clients.
apply NoDup_cons.
- in_crush. discriminate.
- apply NoDup_map_injective.
+ intros. congruence.
+ apply all_fin_NoDup.
Qed.
Global Instance LockServ_BaseParams : BaseParams :=
{
data   := Data ;
input  := Input ;
output := Output
}.
Global Instance LockServ_MultiParams : MultiParams LockServ_BaseParams :=
{
name := Name ;
msg  := Msg ;
msg_eq_dec := Msg_eq_dec ;
name_eq_dec := Name_eq_dec ;
nodes := Nodes ;
all_names_nodes := In_n_Nodes ;
no_dup_nodes := nodup ;
init_handlers := init_data ;
net_handlers := fun dst src msg s =>
runGenHandler_ignore s (NetHandler dst src msg) ;
input_handlers := fun nm msg s =>
runGenHandler_ignore s (InputHandler nm msg)
}.
(* This is the fundamental safety property of the system: No two different clients can (think they) hold the lock at once. *)
Definition mutual_exclusion (sigma : name -> data) : Prop :=
forall m n,
held (sigma (Client m)) = true ->
held (sigma (Client n)) = true ->
m = n.
(* The system enforces mutual exclusion at the server. Whenever a client believs it holds the lock, that client is at the head of the server's queue. *)
Definition locks_correct (sigma : name -> data) : Prop :=
forall n,
held (sigma (Client n)) = true ->
exists t,
queue (sigma Server) = n :: t.
Proof using.
unfold locks_correct, mutual_exclusion.
intros.
repeat find_apply_hyp_hyp.
break_exists.
find_rewrite. find_inversion.
auto.
Qed.
Definition valid_unlock q h c p :=
pSrc p = Client c /\
(exists t, q = c :: t) /\
h = false.
Definition locks_correct_unlock (sigma : name -> data) (p : packet) : Prop :=
pBody p = Unlock ->
exists c, valid_unlock (queue (sigma Server)) (held (sigma (Client c))) c p.
Definition valid_locked q h c p :=
pDst p = Client c /\
(exists t, q = c :: t) /\
h = false.
Definition locks_correct_locked (sigma : name -> data) (p : packet) : Prop :=
pBody p = Locked ->
exists c, valid_locked (queue (sigma Server)) (held (sigma (Client c))) c p.
Definition LockServ_network_invariant (sigma : name -> data) (p : packet) : Prop :=
locks_correct_unlock sigma p /\
locks_correct_locked sigma p.
Definition LockServ_network_network_invariant (p q : packet) : Prop :=
(pBody p = Unlock -> pBody q = Unlock -> False) /\
(pBody p = Locked -> pBody q = Unlock -> False) /\
(pBody p = Unlock -> pBody q = Locked -> False) /\
(pBody p = Locked -> pBody q = Locked -> False).
Proof using.
unfold LockServ_network_network_invariant.
intuition.
Qed.
Proof using.
unfold locks_correct. simpl. discriminate.
Qed.
Proof using.
handler_unfold.
intros.
repeat break_match; repeat tuple_inversion;
subst; simpl in *; subst; simpl in *.
- left. eexists. intuition.
- left. eexists. intuition.
- left. eexists. intuition.
- auto.
- auto.
Qed.
Proof using.
unfold locks_correct.
intuition.
destruct (Name_eq_dec (Client x) (Client n)).
- find_inversion. exfalso.
rewrite_update.
congruence.
- rewrite_update.
auto.
Qed.
Ltac set_up_input_handlers :=
intros;
find_apply_lem_hyp InputHandler_cases;
intuition idtac; try break_exists; intuition idtac; subst;
repeat find_rewrite;
simpl in *; intuition idtac; repeat find_inversion;
try now rewrite update_nop_ext.
Proof using.
set_up_input_handlers;
auto using locks_correct_update_false.
Qed.
Proof using.
handler_unfold.
intros.
repeat break_match; repeat tuple_inversion; subst; auto.
Qed.
Proof using.
handler_unfold.
intros.
repeat break_match; repeat tuple_inversion; subst.
- find_apply_lem_hyp null_sound. find_rewrite. simpl.
intuition. left. eexists. intuition.
- simpl. find_apply_lem_hyp null_false_neq_nil.
intuition. left. eexists. intuition.
- simpl. auto.
- simpl. destruct st; simpl in *; subst; auto.
- simpl in *. intuition.
- simpl in *. intuition eauto.
- simpl. intuition.
Qed.
Definition at_head_of_queue sigma c := (exists t, queue (sigma Server) = c :: t).
Proof using.
unfold at_head_of_queue.
firstorder.
Qed.
Proof using.
unfold locks_correct.
intros.
destruct (Name_eq_dec (Client c) (Client n)); rewrite_update; try find_inversion; auto.
Qed.
Proof using.
unfold locks_correct_locked.
firstorder.
repeat find_rewrite. find_inversion.
eauto using at_head_of_queue_intro.
Qed.
Proof using.
unfold locks_correct.
intros.
rewrite_update.
now find_higher_order_rewrite.
Qed.
Proof using.
unfold locks_correct.
intros.
find_apply_hyp_hyp. break_exists.
eauto using at_head_of_queue_intro.
Qed.
Proof using.
unfold at_head_of_queue.
firstorder.
congruence.
Qed.
Proof using.
intuition.
destruct (held (sigma (Client c))) eqn:?; auto.
exfalso. eauto using at_head_of_nil, locks_correct_true_at_head_of_queue.
Qed.
Proof using.
intros.
destruct (held (sigma (Client c))) eqn:?; auto.
firstorder.
find_copy_apply_lem_hyp locks_correct_true_at_head_of_queue; auto.
unfold at_head_of_queue in *. break_exists.
congruence.
Qed.
Proof using.
unfold locks_correct, at_head_of_queue.
firstorder.
rewrite_update.
eauto.
Qed.
Proof using.
unfold at_head_of_queue.
intuition. break_exists.
rewrite_update.
find_rewrite.
eauto.
Qed.
Ltac set_up_net_handlers :=
intros;
match goal with
| [ H : context [ NetHandler (pDst ?p) _ _ _ ] |- _ ] =>
destruct (pDst p) eqn:?
end; simpl in *;
[find_apply_lem_hyp ClientNetHandler_cases |
find_apply_lem_hyp ServerNetHandler_cases; intuition; try break_exists ];
intuition; subst;
simpl in *; intuition;
repeat find_rewrite;
repeat find_inversion;
simpl in *;
try now rewrite update_nop_ext.
Proof using.
set_up_net_handlers;
eauto using
locks_correct_update_true, locks_correct_locked_at_head,
all_clients_false_locks_correct_server_update, empty_queue_all_clients_false,
locks_correct_at_head_preserved, snoc_at_head_of_queue_preserved,
all_clients_false_locks_correct_server_update, unlock_in_flight_all_clients_false.
Qed.
Proof using.
unfold locks_correct_unlock.
intuition. congruence.
Qed.
Proof using.
unfold locks_correct_unlock.
intuition. congruence.
Qed.
Proof using.
set_up_input_handlers.
destruct (pBody p) eqn:?.
- auto using locks_correct_unlock_sent_lock.
- now erewrite unlock_in_flight_all_clients_false in * by eauto.
- auto using locks_correct_unlock_sent_locked.
Qed.
Proof using.
intros.
destruct (held (sigma (Client c))) eqn:?; auto.
firstorder.
find_copy_apply_lem_hyp locks_correct_true_at_head_of_queue; auto.
unfold at_head_of_queue in *. break_exists.
congruence.
Qed.
Proof using.
unfold locks_correct_locked.
intuition. congruence.
Qed.
Proof using.
unfold locks_correct_locked.
intuition. congruence.
Qed.
Proof using.
set_up_input_handlers.
destruct (pBody p) eqn:?.
- auto using locks_correct_locked_sent_lock.
- auto using locks_correct_locked_sent_unlock.
- now erewrite locked_in_flight_all_clients_false in * by eauto.
Qed.
Proof using.
unfold locks_correct_unlock, valid_unlock.
intros.
exists x.
intuition; now rewrite_update.
Qed.
Proof using.
set_up_input_handlers;
auto using locks_correct_unlock_sent_lock,
locks_correct_unlock_true_to_false,
locks_correct_true_at_head_of_queue.
Qed.
Proof using.
set_up_input_handlers;
auto using locks_correct_locked_sent_lock, locks_correct_locked_sent_unlock.
Qed.
Proof using.
unfold LockServ_network_network_invariant.
intros.
destruct (pBody q); intuition; try discriminate.
Qed.
Proof using.
unfold LockServ_network_network_invariant.
intros.
destruct (pBody q); intuition; try discriminate.
Qed.
Proof using.
unfold locks_correct_unlock.
intros.
find_apply_hyp_hyp. clear H1.
break_exists.
unfold valid_unlock in *. intuition.
break_exists.
repeat find_rewrite. repeat find_inversion.
eauto using at_head_of_queue_intro.
Qed.
Proof using.
unfold locks_correct_unlock, valid_unlock.
intuition.
break_exists.
exists x.
intuition.
- firstorder.
- now rewrite_update.
Qed.
Proof using.
unfold at_head_of_queue.
firstorder.
congruence.
Qed.
Proof using.
set_up_net_handlers;
eauto using locks_correct_unlock_sent_lock, nwnw_locked_lock,
locks_correct_unlock_at_head_preserved, snoc_at_head_of_queue_preserved,
nwnw_unlock_lock, nil_at_head_of_queue_preserved.
Qed.
Proof using.
unfold locks_correct_locked, valid_locked.
intuition.
break_exists.
exists x.
intuition.
- firstorder.
- now rewrite_update.
Qed.
Proof using.
set_up_net_handlers;
eauto using locks_correct_locked_sent_lock, nwnw_locked_lock,
locks_correct_locked_at_head_preserved, snoc_at_head_of_queue_preserved,
nwnw_unlock_lock, nil_at_head_of_queue_preserved.
Qed.
Proof using.
set_up_net_handlers;
auto using locks_correct_unlock_sent_locked.
Qed.
Proof using.
unfold locks_correct_locked, valid_locked.
intros.
exists c.
intuition.
- exists t. now rewrite_update.
- now rewrite_update.
Qed.
Proof using.
set_up_net_handlers;
eauto using locks_correct_locked_intro,
empty_queue_all_clients_false,
unlock_in_flight_all_clients_false.
Qed.
Proof using.
unfold LockServ_network_network_invariant.
intuition; simpl in *; congruence.
Qed.
Proof using.
unfold LockServ_network_invariant.
set_up_input_handlers.
- auto using nwnw_sym, nwnw_lock.
- destruct (pBody p) eqn:?.
+ auto using nwnw_lock.
+ now erewrite unlock_in_flight_all_clients_false in * by eauto.
+ now erewrite locked_in_flight_all_clients_false in * by eauto.
Qed.
Proof using.
set_up_input_handlers.
Qed.
Proof using.
unfold LockServ_network_invariant,
locks_correct_unlock, locks_correct_locked,
valid_unlock, valid_locked.
intuition.
destruct (pBody p) eqn:?; intuition; break_exists; intuition; break_exists;
congruence.
Qed.
Proof using.
set_up_net_handlers;
eauto using nwnw_sym, nwnw_lock, nw_empty_queue_lock, nwnw_unlock_lock.
Qed.
Proof using.
set_up_net_handlers.
Qed.
Instance LockServ_Decompositition : Decomposition _ LockServ_MultiParams.
apply Build_Decomposition with (state_invariant := locks_correct)
(network_invariant := LockServ_network_invariant)
(network_network_invariant := LockServ_network_network_invariant);
simpl; intros; monad_unfold; repeat break_let; repeat find_inversion.
- auto using nwnw_sym.
- auto using locks_correct_init.
- eauto using locks_correct_input_handlers.
- unfold LockServ_network_invariant in *. intuition.
eauto using locks_correct_net_handlers.
- unfold LockServ_network_invariant in *.
intuition eauto using locks_correct_unlock_input_handlers_old,
locks_correct_locked_input_handlers_old.
- unfold LockServ_network_invariant in *.
intuition eauto using locks_correct_unlock_input_handlers_new,
locks_correct_locked_input_handlers_new.
- unfold LockServ_network_invariant in *.
intuition eauto using locks_correct_unlock_net_handlers_old,
locks_correct_locked_net_handlers_old.
- unfold LockServ_network_invariant in *.
intuition eauto using locks_correct_unlock_net_handlers_new,
locks_correct_locked_net_handlers_new.
- eauto using LockServ_nwnw_input_handlers_old_new.
- eauto using LockServ_nwnw_input_handlers_new_new.
- eauto using LockServ_nwnw_net_handlers_old_new.
- eauto using LockServ_nwnw_net_handlers_new_new.
Defined.
Proof using.
pose proof decomposition_invariant.
find_apply_lem_hyp inductive_invariant_true_in_reachable.
unfold true_in_reachable in *.
intros.
apply locks_correct_implies_mutex.
match goal with
| [ H : _ |- _ ] => apply H
end.
auto.
Qed.
Fixpoint last_holder' (holder : option Client_index) (trace : list (name * (input + list output))) : option Client_index :=
match trace with
| [] => holder
| (Client n, inl Unlock) :: tr => match holder with
| None => last_holder' holder tr
| Some m => if fin_eq_dec _ n m
then last_holder' None tr
else last_holder' holder tr
end
| (Client n, inr [Locked]) :: tr => last_holder' (Some n) tr
| (n, _) :: tr => last_holder' holder tr
end.
Fixpoint trace_mutual_exclusion' (holder : option Client_index) (trace : list (name * (input + list output))) : Prop :=
match trace with
| [] => True
| (Client n, (inl Unlock)) :: tr' => match holder with
| Some m => if fin_eq_dec _ n m
then trace_mutual_exclusion' None tr'
else trace_mutual_exclusion' holder tr'
| _ => trace_mutual_exclusion' holder tr'
end
| (n, (inl _)) :: tr' => trace_mutual_exclusion' holder tr'
| (Client n, (inr [Locked])) :: tr' => match holder with
| None => trace_mutual_exclusion' (Some n) tr'
| Some _ => False
end
| (_, (inr [])) :: tr' => trace_mutual_exclusion' holder tr'
| (_, (inr _)) :: tr' => False
end.
Definition trace_mutual_exclusion (trace : list (name * (input + list output))) : Prop :=
trace_mutual_exclusion' None trace.
Definition last_holder (trace : list (name * (input + list output))) : option Client_index :=
last_holder' None trace.

Lemma cross_relation :
forall (P : network -> list (name * (input + list output)) -> Prop),
P step_async_init [] ->
(forall st st' tr ev,
step_async_star step_async_init st tr ->
P st tr ->
step_async st st' ev ->
P st' (tr ++ ev)) ->
forall st tr,
step_async_star step_async_init st tr ->
P st tr.