Model verifying that wakeup really
can be called after release without causing deadlock.
This commit is contained in:
parent
943fd378a1
commit
949352af66
134
sleep1.p
Normal file
134
sleep1.p
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
/*
|
||||||
|
This file defines a Promela model for xv6's
|
||||||
|
acquire, release, sleep, and wakeup, along with
|
||||||
|
a model of a simple producer/consumer queue.
|
||||||
|
|
||||||
|
To run:
|
||||||
|
spinp sleep1.p
|
||||||
|
|
||||||
|
(You may need to install Spin, available at http://spinroot.com/.)
|
||||||
|
|
||||||
|
After a successful run spin prints something like:
|
||||||
|
|
||||||
|
unreached in proctype consumer
|
||||||
|
(0 of 37 states)
|
||||||
|
unreached in proctype producer
|
||||||
|
(0 of 23 states)
|
||||||
|
|
||||||
|
After an unsuccessful run, the spinp script prints
|
||||||
|
an execution trace that causes a deadlock.
|
||||||
|
|
||||||
|
The safe body of producer reads:
|
||||||
|
|
||||||
|
acquire(lk);
|
||||||
|
x = value; value = x + 1; x = 0;
|
||||||
|
wakeup(0);
|
||||||
|
release(lk);
|
||||||
|
i = i + 1;
|
||||||
|
|
||||||
|
If this is changed to:
|
||||||
|
|
||||||
|
x = value; value = x + 1; x = 0;
|
||||||
|
acquire(lk);
|
||||||
|
wakeup(0);
|
||||||
|
release(lk);
|
||||||
|
i = i + 1;
|
||||||
|
|
||||||
|
then a deadlock can happen, because the non-atomic
|
||||||
|
increment of value conflicts with the non-atomic
|
||||||
|
decrement in consumer, causing value to have a bad value.
|
||||||
|
Try this.
|
||||||
|
|
||||||
|
If it is changed to:
|
||||||
|
|
||||||
|
acquire(lk);
|
||||||
|
x = value; value = x + 1; x = 0;
|
||||||
|
release(lk);
|
||||||
|
wakeup(0);
|
||||||
|
i = i + 1;
|
||||||
|
|
||||||
|
then nothing bad happens: it is okay to wakeup after release
|
||||||
|
instead of before, although it seems morally wrong.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ITER 4
|
||||||
|
#define N 2
|
||||||
|
|
||||||
|
bit lk;
|
||||||
|
byte value;
|
||||||
|
bit sleeping[N];
|
||||||
|
|
||||||
|
inline acquire(x)
|
||||||
|
{
|
||||||
|
atomic { x == 0; x = 1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
inline release(x)
|
||||||
|
{
|
||||||
|
assert x==1;
|
||||||
|
x = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
inline sleep(cond, lk)
|
||||||
|
{
|
||||||
|
assert !sleeping[_pid];
|
||||||
|
if
|
||||||
|
:: cond ->
|
||||||
|
skip
|
||||||
|
:: else ->
|
||||||
|
atomic { release(lk); sleeping[_pid] = 1 };
|
||||||
|
sleeping[_pid] == 0;
|
||||||
|
acquire(lk)
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
inline wakeup()
|
||||||
|
{
|
||||||
|
w = 0;
|
||||||
|
do
|
||||||
|
:: w < N ->
|
||||||
|
sleeping[w] = 0;
|
||||||
|
w = w + 1
|
||||||
|
:: else ->
|
||||||
|
break
|
||||||
|
od
|
||||||
|
}
|
||||||
|
|
||||||
|
active[N] proctype consumer()
|
||||||
|
{
|
||||||
|
byte i, x;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
do
|
||||||
|
:: i < ITER ->
|
||||||
|
acquire(lk);
|
||||||
|
sleep(value > 0, lk);
|
||||||
|
x = value; value = x - 1; x = 0;
|
||||||
|
release(lk);
|
||||||
|
i = i + 1;
|
||||||
|
:: else ->
|
||||||
|
break
|
||||||
|
od;
|
||||||
|
i = 0;
|
||||||
|
skip
|
||||||
|
}
|
||||||
|
|
||||||
|
active[N] proctype producer()
|
||||||
|
{
|
||||||
|
byte i, x, w;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
do
|
||||||
|
:: i < ITER ->
|
||||||
|
acquire(lk);
|
||||||
|
x = value; value = x + 1; x = 0;
|
||||||
|
release(lk);
|
||||||
|
wakeup();
|
||||||
|
i = i + 1;
|
||||||
|
:: else ->
|
||||||
|
break
|
||||||
|
od;
|
||||||
|
i = 0;
|
||||||
|
skip
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue