convert from svn repository: remove tags directory
[lttv.git] / trunk / verif / nico-md-merge / pan.spin
CommitLineData
dc45444e 1#define BUFSIZE 8
2/* LTTng ltt-tracer.c atomic lockless buffering scheme Promela model v2
3 * Created for the Spin validator.
4 * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
5 * October 2008
6
7 * TODO : create test cases that will generate an overflow on the offset and
8 * counter type. Counter types smaller than a byte should be used.
9
10 * Promela only has unsigned char, no signed char.
11 * Because detection of difference < 0 depends on a signed type, but we want
12 * compactness, check also for the values being higher than half of the unsigned
13 * char range (and consider them negative). The model, by design, does not use
14 * offsets or counts higher than 127 because we would then have to use a larger
15 * type (short or int).
16 */
17#define HALF_UCHAR (255/2)
18
19/* NUMPROCS 4 : causes event loss with some reader timings.
20 * e.g. 3 events, 1 switch, 1 event (lost, buffer full), read 1 subbuffer
21 */
22#define NUMPROCS 4
23
24/* NUMPROCS 3 : does not cause event loss because buffers are big enough.
25 * #define NUMPROCS 3
26 * e.g. 3 events, 1 switch, read 1 subbuffer
27 */
28
29#define NUMSWITCH 1
30#ifndef BUFSIZE
31#define BUFSIZE 4
32#endif
33#define NR_SUBBUFS 2
34#define SUBBUF_SIZE (BUFSIZE / NR_SUBBUFS)
35
36/* Writer counters
37*/
38byte write_off = 0;
39byte commit_count[NR_SUBBUFS];
40
41/* <formal_verif> */
42byte _commit_sum;
43/* </formal_verif> */
44
45/* Reader counters
46*/
47byte read_off = 0;
48
49byte events_lost = 0;
50byte refcount = 0;
51
52bool deliver = 0;
53
54//#ifdef RACE_TEST
55/* buffer slot in-use bit. Detects racy use (more than a single process
56 * accessing a slot at any given step).
57 */
58bool buffer_use[BUFSIZE];
59//#endif
60
61/* Proceed to a sub-subber switch is needed.
62 * Used in a periodical timer interrupt to fill and ship the current subbuffer
63 * to the reader so we can guarantee a steady flow. If a subbuffer is
64 * completely empty, do not switch.
65 * Also used as "finalize" operation to complete the last subbuffer after
66 * all writers have finished so the last subbuffer can be read by the reader.
67 */
68proctype switcher()
69{
70 byte prev_off, new_off, tmp_commit;
71 byte size;
72
73cmpxchg_loop:
74 atomic {
75 prev_off = write_off;
76 size = SUBBUF_SIZE - (prev_off % SUBBUF_SIZE);
77 new_off = prev_off + size;
78 if
79 :: (new_off - read_off > BUFSIZE && new_off - read_off < HALF_UCHAR)
80 || size == SUBBUF_SIZE ->
81 refcount = refcount - 1;
82 goto not_needed;
83 :: else -> skip
84 fi;
85 }
86 atomic {
87 if
88 :: prev_off != write_off -> goto cmpxchg_loop
89 :: else -> write_off = new_off;
90 fi;
91 }
92
93 atomic {
94 tmp_commit = commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] + size;
95 /* <formal_verif> */
96 _commit_sum = _commit_sum - commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE]
97 + tmp_commit;
98 /* </formal_verif> */
99 commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] = tmp_commit;
100 if
101 :: (((prev_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS) + SUBBUF_SIZE -
102 tmp_commit
103 -> deliver = 1
104 :: else
105 -> skip
106 fi;
107 refcount = refcount - 1;
108 }
109not_needed:
110 skip;
111}
112
113/* tracer
114 * Writes 1 byte of information in the buffer at the current
115 * "write_off" position and then increment the commit_count of the sub-buffer
116 * the information has been written to.
117 */
118proctype tracer()
119{
120 byte size = 1;
121 byte prev_off, new_off, tmp_commit;
122 byte i, j;
123
124cmpxchg_loop:
125 atomic {
126 prev_off = write_off;
127 new_off = prev_off + size;
128 }
129 atomic {
130 if
131 :: new_off - read_off > BUFSIZE && new_off - read_off < HALF_UCHAR ->
132 goto lost
133 :: else -> skip
134 fi;
135 }
136 atomic {
137 if
138 :: prev_off != write_off -> goto cmpxchg_loop
139 :: else -> write_off = new_off;
140 fi;
141 i = 0;
142 do
143 :: i < size ->
144 assert(buffer_use[(prev_off + i) % BUFSIZE] == 0);
145 buffer_use[(prev_off + i) % BUFSIZE] = 1;
146 i++
147 :: i >= size -> break
148 od;
149 }
150
151 /* writing to buffer...
152 */
153
154 atomic {
155 i = 0;
156 do
157 :: i < size ->
158 buffer_use[(prev_off + i) % BUFSIZE] = 0;
159 i++
160 :: i >= size -> break
161 od;
162 tmp_commit = commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] + size;
163 /* <formal_verif> */
164 _commit_sum = _commit_sum - commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE]
165 + tmp_commit;
166 /* </formal_verif> */
167 commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] = tmp_commit;
168 if
169 :: (((prev_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS) + SUBBUF_SIZE -
170 tmp_commit
171 -> deliver = 1
172 :: else
173 -> skip
174 fi;
175 }
176 atomic {
177 goto end;
178lost:
179 events_lost++;
180end:
181 refcount = refcount - 1;
182 }
183}
184
185/* reader
186 * Read the information sub-buffer per sub-buffer when available.
187 *
188 * Reads the information as soon as it is ready, or may be delayed by
189 * an asynchronous delivery. Being modeled as a process insures all cases
190 * (scheduled very quickly or very late, causing event loss) are covered.
191 * Only one reader per buffer (normally ensured by a mutex). This is modeled
192 * by using a single reader process.
193 */
194proctype reader()
195{
196 byte i, j;
197
198 do
199 :: (write_off / SUBBUF_SIZE) - (read_off / SUBBUF_SIZE) > 0
200 && (write_off / SUBBUF_SIZE) - (read_off / SUBBUF_SIZE) < HALF_UCHAR
201 && (commit_count[(read_off % BUFSIZE) / SUBBUF_SIZE]
202 - SUBBUF_SIZE - (((read_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS)
203 == 0) ->
204 atomic {
205 i = 0;
206 do
207 :: i < SUBBUF_SIZE ->
208 assert(buffer_use[(read_off + i) % BUFSIZE] == 0);
209 buffer_use[(read_off + i) % BUFSIZE] = 1;
210 i++
211 :: i >= SUBBUF_SIZE -> break
212 od;
213 }
214
215 /* reading from buffer...
216 */
217
218 atomic {
219 i = 0;
220 do
221 :: i < SUBBUF_SIZE ->
222 buffer_use[(read_off + i) % BUFSIZE] = 0;
223 i++
224 :: i >= SUBBUF_SIZE -> break
225 od;
226 read_off = read_off + SUBBUF_SIZE;
227 }
228 :: read_off >= (NUMPROCS - events_lost) -> break;
229 od;
230}
231
232/* Waits for all tracer and switcher processes to finish before finalizing
233 * the buffer. Only after that will the reader be allowed to read the
234 * last subbuffer.
235 */
236proctype cleaner()
237{
238 atomic {
239 do
240 :: refcount == 0 ->
241 refcount = refcount + 1;
242 run switcher(); /* Finalize the last sub-buffer so it can be read. */
243 break;
244 od;
245 }
246}
247
248init {
249 byte i = 0;
250 byte j = 0;
251 byte sum = 0;
252 byte commit_sum = 0;
253
254 atomic {
255 i = 0;
256 do
257 :: i < NR_SUBBUFS ->
258 commit_count[i] = 0;
259 i++
260 :: i >= NR_SUBBUFS -> break
261 od;
262 /* <formal_verif> */
263 _commit_sum = 0;
264 /* </formal_verif> */
265 i = 0;
266 do
267 :: i < BUFSIZE ->
268 buffer_use[i] = 0;
269 i++
270 :: i >= BUFSIZE -> break
271 od;
272 run reader();
273 run cleaner();
274 i = 0;
275 do
276 :: i < NUMPROCS ->
277 refcount = refcount + 1;
278 run tracer();
279 i++
280 :: i >= NUMPROCS -> break
281 od;
282 i = 0;
283 do
284 :: i < NUMSWITCH ->
285 refcount = refcount + 1;
286 run switcher();
287 i++
288 :: i >= NUMSWITCH -> break
289 od;
290 }
291}
292
This page took 0.031685 seconds and 4 git commands to generate.