123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- /*
- * This model describes a bug in aio_notify. If ctx->notifier is
- * cleared too late, a wakeup could be lost.
- *
- * Author: Paolo Bonzini <pbonzini@redhat.com>
- *
- * This file is in the public domain. If you really want a license,
- * the WTFPL will do.
- *
- * To verify the buggy version:
- * spin -a -DBUG docs/aio_notify_bug.promela
- * gcc -O2 pan.c
- * ./a.out -a -f
- *
- * To verify the fixed version:
- * spin -a docs/aio_notify_bug.promela
- * gcc -O2 pan.c
- * ./a.out -a -f
- *
- * Add -DCHECK_REQ to test an alternative invariant and the
- * "notify_me" optimization.
- */
- int notify_me;
- bool event;
- bool req;
- bool notifier_done;
- #ifdef CHECK_REQ
- #define USE_NOTIFY_ME 1
- #else
- #define USE_NOTIFY_ME 0
- #endif
- active proctype notifier()
- {
- do
- :: true -> {
- req = 1;
- if
- :: !USE_NOTIFY_ME || notify_me -> event = 1;
- :: else -> skip;
- fi
- }
- :: true -> break;
- od;
- notifier_done = 1;
- }
- #ifdef BUG
- #define AIO_POLL \
- notify_me++; \
- if \
- :: !req -> { \
- if \
- :: event -> skip; \
- fi; \
- } \
- :: else -> skip; \
- fi; \
- notify_me--; \
- \
- req = 0; \
- event = 0;
- #else
- #define AIO_POLL \
- notify_me++; \
- if \
- :: !req -> { \
- if \
- :: event -> skip; \
- fi; \
- } \
- :: else -> skip; \
- fi; \
- notify_me--; \
- \
- event = 0; \
- req = 0;
- #endif
- active proctype waiter()
- {
- do
- :: true -> AIO_POLL;
- od;
- }
- /* Same as waiter(), but disappears after a while. */
- active proctype temporary_waiter()
- {
- do
- :: true -> AIO_POLL;
- :: true -> break;
- od;
- }
- #ifdef CHECK_REQ
- never {
- do
- :: req -> goto accept_if_req_not_eventually_false;
- :: true -> skip;
- od;
- accept_if_req_not_eventually_false:
- if
- :: req -> goto accept_if_req_not_eventually_false;
- fi;
- assert(0);
- }
- #else
- /* There must be infinitely many transitions of event as long
- * as the notifier does not exit.
- *
- * If event stayed always true, the waiters would be busy looping.
- * If event stayed always false, the waiters would be sleeping
- * forever.
- */
- never {
- do
- :: !event -> goto accept_if_event_not_eventually_true;
- :: event -> goto accept_if_event_not_eventually_false;
- :: true -> skip;
- od;
- accept_if_event_not_eventually_true:
- if
- :: !event && notifier_done -> do :: true -> skip; od;
- :: !event && !notifier_done -> goto accept_if_event_not_eventually_true;
- fi;
- assert(0);
- accept_if_event_not_eventually_false:
- if
- :: event -> goto accept_if_event_not_eventually_false;
- fi;
- assert(0);
- }
- #endif
|