|  | /* | 
|  | * 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 |