2queuelive noncomp
In this example, we have two unbounded queues. Commands are sent on queue q1. Periodically, commands are read from q1 and responses are sent on q2. We prove that a response to every command is eventually received at the output of q2.
The proof is done non-compositionally. That is, we prove that the whole system is live using a single instance of the l2s_auto tactic.
include order
instance nat : unbounded_sequence
module signal = {
action raise
specification {
relation now
after init { now := false; }
before raise {
now := true;
now := false;
}
invariant ~now
}
}
module signal1(data) = {
action raise(val:data)
specification {
relation now
var value : data
after init { now := false; }
before raise {
value := val;
now := true;
now := false;
}
invariant ~now
}
}
type id
module isolate unbounded_queue with nat = {
action send(x:id)
action recv returns (x:id, ok:bool)
specification {
var head : nat
var tail : nat
var queue(X:nat) : id
after init {
head := 0;
tail := 0;
}
instance sending : signal1(id)
instance trying : signal
instance receiving : signal1(id)
before send {
queue(tail) := x;
tail := tail.next;
sending.raise(x); # ghost action to signal a send
}
before recv {
trying.raise; # ghost action signalling polling of queue
ok := head < tail;
if ok {
receiving.raise(queue(head)); # ghost action to signal a receive
x := queue(head);
head := head.next;
}
}
}
}
isolate m = {
instance q1 : unbounded_queue
instance q2 : unbounded_queue
action poll = {
var x : id;
var ok : bool;
(x,ok) := q1.recv;
if ok {
q2.send(x);
}
}
temporal property
forall X. ((globally eventually q1.trying.now)
& (globally eventually q2.trying.now)
& (eventually q1.sending.now & q1.sending.value = X) ->
(eventually q2.receiving.now & q2.receiving.value = X))
proof {
tactic skolemize;
tactic l2s_auto with {
definition work_created[1](X) = (X < q1.tail)
definition work_needed[1](X) = ~exists Y. Y < X & q1.queue(Y) = _X
definition work_done[1](X) = X < q1.head
definition work_progress[1] = q1.trying.now
definition work_start[1] = (q1.sending.now & q1.sending.value = _X)
definition work_created[2](X) = (X < q2.tail)
definition work_needed[2](X) = ~exists Y. Y < X & q2.queue(Y) = _X
definition work_done[2](X) = X < q2.head
definition work_progress[2] = q2.trying.now
definition work_start[2] = (q2.sending.now & q2.sending.value = _X)
invariant [foo] ($l2s_init . ~($l2s_g . ~(m.q1.sending.now & m.q1.sending.value = _X)))
}
showgoals
}
} with nat
export m.q1.send
export m.poll
export m.q2.recv