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