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