aio_notify_bug.promela (4164B)
1/* 2 * This model describes a bug in aio_notify. If ctx->notifier is 3 * cleared too late, a wakeup could be lost. 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 -DBUG docs/aio_notify_bug.promela 12 * gcc -O2 pan.c 13 * ./a.out -a -f 14 * 15 * To verify the fixed version: 16 * spin -a docs/aio_notify_bug.promela 17 * gcc -O2 pan.c 18 * ./a.out -a -f 19 * 20 * Add -DCHECK_REQ to test an alternative invariant and the 21 * "notify_me" optimization. 22 */ 23 24int notify_me; 25bool event; 26bool req; 27bool notifier_done; 28 29#ifdef CHECK_REQ 30#define USE_NOTIFY_ME 1 31#else 32#define USE_NOTIFY_ME 0 33#endif 34 35active proctype notifier() 36{ 37 do 38 :: true -> { 39 req = 1; 40 if 41 :: !USE_NOTIFY_ME || notify_me -> event = 1; 42 :: else -> skip; 43 fi 44 } 45 :: true -> break; 46 od; 47 notifier_done = 1; 48} 49 50#ifdef BUG 51#define AIO_POLL \ 52 notify_me++; \ 53 if \ 54 :: !req -> { \ 55 if \ 56 :: event -> skip; \ 57 fi; \ 58 } \ 59 :: else -> skip; \ 60 fi; \ 61 notify_me--; \ 62 \ 63 req = 0; \ 64 event = 0; 65#else 66#define AIO_POLL \ 67 notify_me++; \ 68 if \ 69 :: !req -> { \ 70 if \ 71 :: event -> skip; \ 72 fi; \ 73 } \ 74 :: else -> skip; \ 75 fi; \ 76 notify_me--; \ 77 \ 78 event = 0; \ 79 req = 0; 80#endif 81 82active proctype waiter() 83{ 84 do 85 :: true -> AIO_POLL; 86 od; 87} 88 89/* Same as waiter(), but disappears after a while. */ 90active proctype temporary_waiter() 91{ 92 do 93 :: true -> AIO_POLL; 94 :: true -> break; 95 od; 96} 97 98#ifdef CHECK_REQ 99never { 100 do 101 :: req -> goto accept_if_req_not_eventually_false; 102 :: true -> skip; 103 od; 104 105accept_if_req_not_eventually_false: 106 if 107 :: req -> goto accept_if_req_not_eventually_false; 108 fi; 109 assert(0); 110} 111 112#else 113/* There must be infinitely many transitions of event as long 114 * as the notifier does not exit. 115 * 116 * If event stayed always true, the waiters would be busy looping. 117 * If event stayed always false, the waiters would be sleeping 118 * forever. 119 */ 120never { 121 do 122 :: !event -> goto accept_if_event_not_eventually_true; 123 :: event -> goto accept_if_event_not_eventually_false; 124 :: true -> skip; 125 od; 126 127accept_if_event_not_eventually_true: 128 if 129 :: !event && notifier_done -> do :: true -> skip; od; 130 :: !event && !notifier_done -> goto accept_if_event_not_eventually_true; 131 fi; 132 assert(0); 133 134accept_if_event_not_eventually_false: 135 if 136 :: event -> goto accept_if_event_not_eventually_false; 137 fi; 138 assert(0); 139} 140#endif