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