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