105 lines
2.4 KiB
Promela
105 lines
2.4 KiB
Promela
|
/*
|
||
|
* This model describes the interaction between aio_set_dispatching()
|
||
|
* and aio_notify().
|
||
|
*
|
||
|
* Author: Paolo Bonzini <pbonzini@redhat.com>
|
||
|
*
|
||
|
* This file is in the public domain. If you really want a license,
|
||
|
* the WTFPL will do.
|
||
|
*
|
||
|
* To simulate it:
|
||
|
* spin -p docs/aio_notify.promela
|
||
|
*
|
||
|
* To verify it:
|
||
|
* spin -a docs/aio_notify.promela
|
||
|
* gcc -O2 pan.c
|
||
|
* ./a.out -a
|
||
|
*/
|
||
|
|
||
|
#define MAX 4
|
||
|
#define LAST (1 << (MAX - 1))
|
||
|
#define FINAL ((LAST << 1) - 1)
|
||
|
|
||
|
bool dispatching;
|
||
|
bool event;
|
||
|
|
||
|
int req, done;
|
||
|
|
||
|
active proctype waiter()
|
||
|
{
|
||
|
int fetch, blocking;
|
||
|
|
||
|
do
|
||
|
:: done != FINAL -> {
|
||
|
// Computing "blocking" is separate from execution of the
|
||
|
// "bottom half"
|
||
|
blocking = (req == 0);
|
||
|
|
||
|
// This is our "bottom half"
|
||
|
atomic { fetch = req; req = 0; }
|
||
|
done = done | fetch;
|
||
|
|
||
|
// Wait for a nudge from the other side
|
||
|
do
|
||
|
:: event == 1 -> { event = 0; break; }
|
||
|
:: !blocking -> break;
|
||
|
od;
|
||
|
|
||
|
dispatching = 1;
|
||
|
|
||
|
// If you are simulating this model, you may want to add
|
||
|
// something like this here:
|
||
|
//
|
||
|
// int foo; foo++; foo++; foo++;
|
||
|
//
|
||
|
// This only wastes some time and makes it more likely
|
||
|
// that the notifier process hits the "fast path".
|
||
|
|
||
|
dispatching = 0;
|
||
|
}
|
||
|
:: else -> break;
|
||
|
od
|
||
|
}
|
||
|
|
||
|
active proctype notifier()
|
||
|
{
|
||
|
int next = 1;
|
||
|
int sets = 0;
|
||
|
|
||
|
do
|
||
|
:: next <= LAST -> {
|
||
|
// generate a request
|
||
|
req = req | next;
|
||
|
next = next << 1;
|
||
|
|
||
|
// aio_notify
|
||
|
if
|
||
|
:: dispatching == 0 -> sets++; event = 1;
|
||
|
:: else -> skip;
|
||
|
fi;
|
||
|
|
||
|
// Test both synchronous and asynchronous delivery
|
||
|
if
|
||
|
:: 1 -> do
|
||
|
:: req == 0 -> break;
|
||
|
od;
|
||
|
:: 1 -> skip;
|
||
|
fi;
|
||
|
}
|
||
|
:: else -> break;
|
||
|
od;
|
||
|
printf("Skipped %d event_notifier_set\n", MAX - sets);
|
||
|
}
|
||
|
|
||
|
#define p (done == FINAL)
|
||
|
|
||
|
never {
|
||
|
do
|
||
|
:: 1 // after an arbitrarily long prefix
|
||
|
:: p -> break // p becomes true
|
||
|
od;
|
||
|
do
|
||
|
:: !p -> accept: break // it then must remains true forever after
|
||
|
od
|
||
|
}
|