Examp4
This is the example from section 3.3 of the paper, using a stable scehduler to prove the cascaded queues without using lemmas when the second queue can be full.
include order
instance time : 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
}
}
module isolate unbounded_queue with time = {
action send(x:time)
action recv returns (x:time, ok:bool)
action full returns (x:bool)
specification {
var latest : time
var pending(X:time) : bool
after init {
latest := 0;
pending(X) := false;
}
instance sending : signal1(time)
instance trying : signal
instance receiving : signal1(time)
before send {
require x > latest;
pending(x) := true;
latest := x;
sending.raise(x); # ghost action to signal a send
}
before recv {
trying.raise; # ghost action signalling polling of queue
ok := false;
if some (y:time) pending(y) minimizing y {
ok := true;
x := y;
pending(x) := false;
receiving.raise(x);
}
}
before full {
if ~exists X. pending(X) {
x := false;
}
}
invariant pending(X) -> X <= latest
temporal property [lpq]
(globally eventually trying.now)
->
forall X. globally (sending.now & sending.value = X) ->
(eventually receiving.now & receiving.value = X)
proof {
tactic skolemize;
tactic l2s_auto4 with {
definition work_created(X) = pending(X)
definition work_needed(X) = pending(X) & X <= _X
definition work_done(X:time) = false
definition work_end(X:time) = pending(_X)
definition work_start = ~((sending.now & sending.value = _X) ->
(eventually receiving.now & receiving.value = _X))
definition work_progress = trying.now
}
showgoals
}
}
}
isolate m = {
instance q1 : unbounded_queue
instance q2 : unbounded_queue
instance polling : signal
action poll = {
var x : time;
var ok : bool;
polling.raise;
if ~q2.full {
(x,ok) := q1.recv;
if ok {
q2.send(x);
}
}
}
invariant forall X. q1.pending(X) -> X > q2.latest
invariant q2.latest <= q1.latest
temporal property
forall X. ((globally eventually polling.now)
& (globally eventually q2.trying.now)
-> (globally q1.sending.now & q1.sending.value = X ->
(eventually q2.receiving.now & q2.receiving.value = X)))
proof {
tactic skolemize;
showgoals;
tactic ranking with {
definition work_created[1](X) = q1.pending(X)
definition work_needed[1](X) = q1.pending(X) & X <= _X
definition work_invar[1] = q1.pending(_X) | q2.pending(_X)
definition work_progress[1] = polling.now
definition work_helpful[1] = ~exists X. q2.pending(X)
definition work_created[2](X) = q1.pending(X) | q2.pending(X)
definition work_needed[2](X) = (q1.pending(X) | q2.pending(X)) & X <= _X
definition work_invar[2] = q1.pending(_X) | q2.pending(_X)
definition work_progress[2] = q2.trying.now
definition work_helpful[2] = exists X. q2.pending(X)
}
showgoals
}
} with time
export m.q1.send
export m.poll
export m.q2.recv