aio_notify_accept.promela (4052B)
1/* 2 * This model describes the interaction between ctx->notified 3 * and ctx->notifier. 4 * 5 * Author: Paolo Bonzini <pbonzini@redhat.com> 6 * 7 * This file is in the public domain. If you really want a license, 8 * the WTFPL will do. 9 * 10 * To verify the buggy version: 11 * spin -a -DBUG1 docs/aio_notify_bug.promela 12 * gcc -O2 pan.c 13 * ./a.out -a -f 14 * (or -DBUG2) 15 * 16 * To verify the fixed version: 17 * spin -a docs/aio_notify_bug.promela 18 * gcc -O2 pan.c 19 * ./a.out -a -f 20 * 21 * Add -DCHECK_REQ to test an alternative invariant and the 22 * "notify_me" optimization. 23 */ 24 25int notify_me; 26bool notified; 27bool event; 28bool req; 29bool notifier_done; 30 31#ifdef CHECK_REQ 32#define USE_NOTIFY_ME 1 33#else 34#define USE_NOTIFY_ME 0 35#endif 36 37#ifdef BUG 38#error Please define BUG1 or BUG2 instead. 39#endif 40 41active proctype notifier() 42{ 43 do 44 :: true -> { 45 req = 1; 46 if 47 :: !USE_NOTIFY_ME || notify_me -> 48#if defined BUG1 49 /* CHECK_REQ does not detect this bug! */ 50 notified = 1; 51 event = 1; 52#elif defined BUG2 53 if 54 :: !notified -> event = 1; 55 :: else -> skip; 56 fi; 57 notified = 1; 58#else 59 event = 1; 60 notified = 1; 61#endif 62 :: else -> skip; 63 fi 64 } 65 :: true -> break; 66 od; 67 notifier_done = 1; 68} 69 70#define AIO_POLL \ 71 notify_me++; \ 72 if \ 73 :: !req -> { \ 74 if \ 75 :: event -> skip; \ 76 fi; \ 77 } \ 78 :: else -> skip; \ 79 fi; \ 80 notify_me--; \ 81 \ 82 atomic { old = notified; notified = 0; } \ 83 if \ 84 :: old -> event = 0; \ 85 :: else -> skip; \ 86 fi; \ 87 \ 88 req = 0; 89 90active proctype waiter() 91{ 92 bool old; 93 94 do 95 :: true -> AIO_POLL; 96 od; 97} 98 99/* Same as waiter(), but disappears after a while. */ 100active proctype temporary_waiter() 101{ 102 bool old; 103 104 do 105 :: true -> AIO_POLL; 106 :: true -> break; 107 od; 108} 109 110#ifdef CHECK_REQ 111never { 112 do 113 :: req -> goto accept_if_req_not_eventually_false; 114 :: true -> skip; 115 od; 116 117accept_if_req_not_eventually_false: 118 if 119 :: req -> goto accept_if_req_not_eventually_false; 120 fi; 121 assert(0); 122} 123 124#else 125/* There must be infinitely many transitions of event as long 126 * as the notifier does not exit. 127 * 128 * If event stayed always true, the waiters would be busy looping. 129 * If event stayed always false, the waiters would be sleeping 130 * forever. 131 */ 132never { 133 do 134 :: !event -> goto accept_if_event_not_eventually_true; 135 :: event -> goto accept_if_event_not_eventually_false; 136 :: true -> skip; 137 od; 138 139accept_if_event_not_eventually_true: 140 if 141 :: !event && notifier_done -> do :: true -> skip; od; 142 :: !event && !notifier_done -> goto accept_if_event_not_eventually_true; 143 fi; 144 assert(0); 145 146accept_if_event_not_eventually_false: 147 if 148 :: event -> goto accept_if_event_not_eventually_false; 149 fi; 150 assert(0); 151} 152#endif