xref: /openbmc/qemu/docs/spin/aio_notify_accept.promela (revision bbfa326fc8028e275eddf8c9965c2a1b59405b2e)
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