hash table comment fix.
[urcu.git] / formal-model / urcu-nosched-model / result-signal-over-reader / urcu_progress_writer_error.spin.input
CommitLineData
06e8b2a8
MD
1#define WRITER_PROGRESS
2#define GEN_ERROR_WRITER_PROGRESS
3
4#define read_free_race (read_generation[0] == last_free_gen)
5#define read_free (free_done && data_access[0])
6
7#define TEST_SIGNAL
8#define TEST_SIGNAL_ON_READ
9//#define TEST_SIGNAL_ON_WRITE
10
11#define RCU_GP_CTR_BIT (1 << 7)
12#define RCU_GP_CTR_NEST_MASK (RCU_GP_CTR_BIT - 1)
13
14#ifndef READER_NEST_LEVEL
15#define READER_NEST_LEVEL 1
16//#define READER_NEST_LEVEL 2
17#endif
18
19#define REMOTE_BARRIERS
20/*
21 * mem.spin: Promela code to validate memory barriers with OOO memory.
22 *
23 * This program is free software; you can redistribute it and/or modify
24 * it under the terms of the GNU General Public License as published by
25 * the Free Software Foundation; either version 2 of the License, or
26 * (at your option) any later version.
27 *
28 * This program is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 * GNU General Public License for more details.
32 *
33 * You should have received a copy of the GNU General Public License
34 * along with this program; if not, write to the Free Software
35 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
36 *
37 * Copyright (c) 2009 Mathieu Desnoyers
38 */
39
40/* Promela validation variables. */
41
42/* specific defines "included" here */
43/* DEFINES file "included" here */
44
45/* All signal readers have same PID and uses same reader variable */
46#ifdef TEST_SIGNAL_ON_WRITE
47
48#define NR_READERS 1 /* the writer is also a signal reader */
49#define NR_WRITERS 1
50
51#define NR_PROCS 1
52
53#define get_pid() (0)
54
55#elif defined(TEST_SIGNAL_ON_READ)
56
57#define get_pid() ((_pid < 2) -> 0 : 1)
58
59#define NR_READERS 1
60#define NR_WRITERS 1
61
62#define NR_PROCS 2
63
64#else
65
66#define get_pid() (_pid)
67
68#define NR_READERS 1
69#define NR_WRITERS 1
70
71#define NR_PROCS 2
72
73#endif
74
75#define get_readerid() (get_pid())
76
77/*
78 * Each process have its own data in cache. Caches are randomly updated.
79 * smp_wmb and smp_rmb forces cache updates (write and read), smp_mb forces
80 * both.
81 */
82
83typedef per_proc_byte {
84 byte val[NR_PROCS];
85};
86
87/* Bitfield has a maximum of 8 procs */
88typedef per_proc_bit {
89 byte bitfield;
90};
91
92#define DECLARE_CACHED_VAR(type, x) \
93 type mem_##x; \
94 per_proc_##type cached_##x; \
95 per_proc_bit cache_dirty_##x;
96
97#define INIT_CACHED_VAR(x, v, j) \
98 mem_##x = v; \
99 cache_dirty_##x.bitfield = 0; \
100 j = 0; \
101 do \
102 :: j < NR_PROCS -> \
103 cached_##x.val[j] = v; \
104 j++ \
105 :: j >= NR_PROCS -> break \
106 od;
107
108#define IS_CACHE_DIRTY(x, id) (cache_dirty_##x.bitfield & (1 << id))
109
110#define READ_CACHED_VAR(x) (cached_##x.val[get_pid()])
111
112#define WRITE_CACHED_VAR(x, v) \
113 atomic { \
114 cached_##x.val[get_pid()] = v; \
115 cache_dirty_##x.bitfield = \
116 cache_dirty_##x.bitfield | (1 << get_pid()); \
117 }
118
119#define CACHE_WRITE_TO_MEM(x, id) \
120 if \
121 :: IS_CACHE_DIRTY(x, id) -> \
122 mem_##x = cached_##x.val[id]; \
123 cache_dirty_##x.bitfield = \
124 cache_dirty_##x.bitfield & (~(1 << id)); \
125 :: else -> \
126 skip \
127 fi;
128
129#define CACHE_READ_FROM_MEM(x, id) \
130 if \
131 :: !IS_CACHE_DIRTY(x, id) -> \
132 cached_##x.val[id] = mem_##x;\
133 :: else -> \
134 skip \
135 fi;
136
137/*
138 * May update other caches if cache is dirty, or not.
139 */
140#define RANDOM_CACHE_WRITE_TO_MEM(x, id)\
141 if \
142 :: 1 -> CACHE_WRITE_TO_MEM(x, id); \
143 :: 1 -> skip \
144 fi;
145
146#define RANDOM_CACHE_READ_FROM_MEM(x, id)\
147 if \
148 :: 1 -> CACHE_READ_FROM_MEM(x, id); \
149 :: 1 -> skip \
150 fi;
151
152/*
153 * Remote barriers tests the scheme where a signal (or IPI) is sent to all
154 * reader threads to promote their compiler barrier to a smp_mb().
155 */
156#ifdef REMOTE_BARRIERS
157
158inline smp_rmb_pid(i, j)
159{
160 atomic {
161 CACHE_READ_FROM_MEM(urcu_gp_ctr, i);
162 j = 0;
163 do
164 :: j < NR_READERS ->
165 CACHE_READ_FROM_MEM(urcu_active_readers[j], i);
166 j++
167 :: j >= NR_READERS -> break
168 od;
169 CACHE_READ_FROM_MEM(generation_ptr, i);
170 }
171}
172
173inline smp_wmb_pid(i, j)
174{
175 atomic {
176 CACHE_WRITE_TO_MEM(urcu_gp_ctr, i);
177 j = 0;
178 do
179 :: j < NR_READERS ->
180 CACHE_WRITE_TO_MEM(urcu_active_readers[j], i);
181 j++
182 :: j >= NR_READERS -> break
183 od;
184 CACHE_WRITE_TO_MEM(generation_ptr, i);
185 }
186}
187
188inline smp_mb_pid(i, j)
189{
190 atomic {
191#ifndef NO_WMB
192 smp_wmb_pid(i, j);
193#endif
194#ifndef NO_RMB
195 smp_rmb_pid(i, j);
196#endif
197#ifdef NO_WMB
198#ifdef NO_RMB
199 ooo_mem(j);
200#endif
201#endif
202 }
203}
204
205/*
206 * Readers do a simple barrier(), writers are doing a smp_mb() _and_ sending a
207 * signal or IPI to have all readers execute a smp_mb.
208 * We are not modeling the whole rendez-vous between readers and writers here,
209 * we just let the writer update each reader's caches remotely.
210 */
211inline smp_mb_writer(i, j)
212{
213 smp_mb_pid(get_pid(), j);
214 i = 0;
215 do
216 :: i < NR_READERS ->
217 smp_mb_pid(i, j);
218 i++;
219 :: i >= NR_READERS -> break
220 od;
221 smp_mb_pid(get_pid(), j);
222}
223
224inline smp_mb_reader(i, j)
225{
226 skip;
227}
228
229#else
230
231inline smp_rmb(i, j)
232{
233 atomic {
234 CACHE_READ_FROM_MEM(urcu_gp_ctr, get_pid());
235 i = 0;
236 do
237 :: i < NR_READERS ->
238 CACHE_READ_FROM_MEM(urcu_active_readers[i], get_pid());
239 i++
240 :: i >= NR_READERS -> break
241 od;
242 CACHE_READ_FROM_MEM(generation_ptr, get_pid());
243 }
244}
245
246inline smp_wmb(i, j)
247{
248 atomic {
249 CACHE_WRITE_TO_MEM(urcu_gp_ctr, get_pid());
250 i = 0;
251 do
252 :: i < NR_READERS ->
253 CACHE_WRITE_TO_MEM(urcu_active_readers[i], get_pid());
254 i++
255 :: i >= NR_READERS -> break
256 od;
257 CACHE_WRITE_TO_MEM(generation_ptr, get_pid());
258 }
259}
260
261inline smp_mb(i, j)
262{
263 atomic {
264#ifndef NO_WMB
265 smp_wmb(i, j);
266#endif
267#ifndef NO_RMB
268 smp_rmb(i, j);
269#endif
270#ifdef NO_WMB
271#ifdef NO_RMB
272 ooo_mem(i);
273#endif
274#endif
275 }
276}
277
278inline smp_mb_writer(i, j)
279{
280 smp_mb(i, j);
281}
282
283inline smp_mb_reader(i, j)
284{
285 smp_mb(i, j);
286}
287
288#endif
289
290/* Keep in sync manually with smp_rmb, wmp_wmb, ooo_mem and init() */
291DECLARE_CACHED_VAR(byte, urcu_gp_ctr);
292/* Note ! currently only two readers */
293DECLARE_CACHED_VAR(byte, urcu_active_readers[NR_READERS]);
294/* pointer generation */
295DECLARE_CACHED_VAR(byte, generation_ptr);
296
297byte last_free_gen = 0;
298bit free_done = 0;
299byte read_generation[NR_READERS];
300bit data_access[NR_READERS];
301
302bit write_lock = 0;
303
304bit init_done = 0;
305
306bit sighand_exec = 0;
307
308inline wait_init_done()
309{
310 do
311 :: init_done == 0 -> skip;
312 :: else -> break;
313 od;
314}
315
316#ifdef TEST_SIGNAL
317
318inline wait_for_sighand_exec()
319{
320 sighand_exec = 0;
321 do
322 :: sighand_exec == 0 -> skip;
323 :: else -> break;
324 od;
325}
326
327#ifdef TOO_BIG_STATE_SPACE
328inline wait_for_sighand_exec()
329{
330 sighand_exec = 0;
331 do
332 :: sighand_exec == 0 -> skip;
333 :: else ->
334 if
335 :: 1 -> break;
336 :: 1 -> sighand_exec = 0;
337 skip;
338 fi;
339 od;
340}
341#endif
342
343#else
344
345inline wait_for_sighand_exec()
346{
347 skip;
348}
349
350#endif
351
352#ifdef TEST_SIGNAL_ON_WRITE
353/* Block on signal handler execution */
354inline dispatch_sighand_write_exec()
355{
356 sighand_exec = 1;
357 do
358 :: sighand_exec == 1 ->
359 skip;
360 :: else ->
361 break;
362 od;
363}
364
365#else
366
367inline dispatch_sighand_write_exec()
368{
369 skip;
370}
371
372#endif
373
374#ifdef TEST_SIGNAL_ON_READ
375/* Block on signal handler execution */
376inline dispatch_sighand_read_exec()
377{
378 sighand_exec = 1;
379 do
380 :: sighand_exec == 1 ->
381 skip;
382 :: else ->
383 break;
384 od;
385}
386
387#else
388
389inline dispatch_sighand_read_exec()
390{
391 skip;
392}
393
394#endif
395
396
397inline ooo_mem(i)
398{
399 atomic {
400 RANDOM_CACHE_WRITE_TO_MEM(urcu_gp_ctr, get_pid());
401 i = 0;
402 do
403 :: i < NR_READERS ->
404 RANDOM_CACHE_WRITE_TO_MEM(urcu_active_readers[i],
405 get_pid());
406 i++
407 :: i >= NR_READERS -> break
408 od;
409 RANDOM_CACHE_WRITE_TO_MEM(generation_ptr, get_pid());
410 RANDOM_CACHE_READ_FROM_MEM(urcu_gp_ctr, get_pid());
411 i = 0;
412 do
413 :: i < NR_READERS ->
414 RANDOM_CACHE_READ_FROM_MEM(urcu_active_readers[i],
415 get_pid());
416 i++
417 :: i >= NR_READERS -> break
418 od;
419 RANDOM_CACHE_READ_FROM_MEM(generation_ptr, get_pid());
420 }
421}
422
423inline wait_for_reader(tmp, tmp2, i, j)
424{
425 do
426 :: 1 ->
427 tmp2 = READ_CACHED_VAR(urcu_active_readers[tmp]);
428 ooo_mem(i);
429 dispatch_sighand_write_exec();
430 if
431 :: (tmp2 & RCU_GP_CTR_NEST_MASK)
432 && ((tmp2 ^ READ_CACHED_VAR(urcu_gp_ctr))
433 & RCU_GP_CTR_BIT) ->
434#ifndef GEN_ERROR_WRITER_PROGRESS
435 smp_mb_writer(i, j);
436#else
437 ooo_mem(i);
438#endif
439 dispatch_sighand_write_exec();
440 :: else ->
441 break;
442 fi;
443 od;
444}
445
446inline wait_for_quiescent_state(tmp, tmp2, i, j)
447{
448 tmp = 0;
449 do
450 :: tmp < NR_READERS ->
451 wait_for_reader(tmp, tmp2, i, j);
452 if
453 :: (NR_READERS > 1) && (tmp < NR_READERS - 1)
454 -> ooo_mem(i);
455 dispatch_sighand_write_exec();
456 :: else
457 -> skip;
458 fi;
459 tmp++
460 :: tmp >= NR_READERS -> break
461 od;
462}
463
464/* Model the RCU read-side critical section. */
465
466#ifndef TEST_SIGNAL_ON_WRITE
467
468inline urcu_one_read(i, j, nest_i, tmp, tmp2)
469{
470 nest_i = 0;
471 do
472 :: nest_i < READER_NEST_LEVEL ->
473 ooo_mem(i);
474 dispatch_sighand_read_exec();
475 tmp = READ_CACHED_VAR(urcu_active_readers[get_readerid()]);
476 ooo_mem(i);
477 dispatch_sighand_read_exec();
478 if
479 :: (!(tmp & RCU_GP_CTR_NEST_MASK))
480 ->
481 tmp2 = READ_CACHED_VAR(urcu_gp_ctr);
482 ooo_mem(i);
483 dispatch_sighand_read_exec();
484 WRITE_CACHED_VAR(urcu_active_readers[get_readerid()],
485 tmp2);
486 :: else ->
487 WRITE_CACHED_VAR(urcu_active_readers[get_readerid()],
488 tmp + 1);
489 fi;
490 smp_mb_reader(i, j);
491 dispatch_sighand_read_exec();
492 nest_i++;
493 :: nest_i >= READER_NEST_LEVEL -> break;
494 od;
495
496 read_generation[get_readerid()] = READ_CACHED_VAR(generation_ptr);
497 data_access[get_readerid()] = 1;
498 data_access[get_readerid()] = 0;
499
500 nest_i = 0;
501 do
502 :: nest_i < READER_NEST_LEVEL ->
503 smp_mb_reader(i, j);
504 dispatch_sighand_read_exec();
505 tmp2 = READ_CACHED_VAR(urcu_active_readers[get_readerid()]);
506 ooo_mem(i);
507 dispatch_sighand_read_exec();
508 WRITE_CACHED_VAR(urcu_active_readers[get_readerid()], tmp2 - 1);
509 nest_i++;
510 :: nest_i >= READER_NEST_LEVEL -> break;
511 od;
512 //ooo_mem(i);
513 //dispatch_sighand_read_exec();
514 //smp_mc(i); /* added */
515}
516
517active proctype urcu_reader()
518{
519 byte i, j, nest_i;
520 byte tmp, tmp2;
521
522 wait_init_done();
523
524 assert(get_pid() < NR_PROCS);
525
526end_reader:
527 do
528 :: 1 ->
529 /*
530 * We do not test reader's progress here, because we are mainly
531 * interested in writer's progress. The reader never blocks
532 * anyway. We have to test for reader/writer's progress
533 * separately, otherwise we could think the writer is doing
534 * progress when it's blocked by an always progressing reader.
535 */
536#ifdef READER_PROGRESS
537progress_reader:
538#endif
539 urcu_one_read(i, j, nest_i, tmp, tmp2);
540 od;
541}
542
543#endif //!TEST_SIGNAL_ON_WRITE
544
545#ifdef TEST_SIGNAL
546/* signal handler reader */
547
548inline urcu_one_read_sig(i, j, nest_i, tmp, tmp2)
549{
550 nest_i = 0;
551 do
552 :: nest_i < READER_NEST_LEVEL ->
553 ooo_mem(i);
554 tmp = READ_CACHED_VAR(urcu_active_readers[get_readerid()]);
555 ooo_mem(i);
556 if
557 :: (!(tmp & RCU_GP_CTR_NEST_MASK))
558 ->
559 tmp2 = READ_CACHED_VAR(urcu_gp_ctr);
560 ooo_mem(i);
561 WRITE_CACHED_VAR(urcu_active_readers[get_readerid()],
562 tmp2);
563 :: else ->
564 WRITE_CACHED_VAR(urcu_active_readers[get_readerid()],
565 tmp + 1);
566 fi;
567 smp_mb_reader(i, j);
568 nest_i++;
569 :: nest_i >= READER_NEST_LEVEL -> break;
570 od;
571
572 read_generation[get_readerid()] = READ_CACHED_VAR(generation_ptr);
573 data_access[get_readerid()] = 1;
574 data_access[get_readerid()] = 0;
575
576 nest_i = 0;
577 do
578 :: nest_i < READER_NEST_LEVEL ->
579 smp_mb_reader(i, j);
580 tmp2 = READ_CACHED_VAR(urcu_active_readers[get_readerid()]);
581 ooo_mem(i);
582 WRITE_CACHED_VAR(urcu_active_readers[get_readerid()], tmp2 - 1);
583 nest_i++;
584 :: nest_i >= READER_NEST_LEVEL -> break;
585 od;
586 //ooo_mem(i);
587 //smp_mc(i); /* added */
588}
589
590active proctype urcu_reader_sig()
591{
592 byte i, j, nest_i;
593 byte tmp, tmp2;
594
595 wait_init_done();
596
597 assert(get_pid() < NR_PROCS);
598
599end_reader:
600 do
601 :: 1 ->
602 wait_for_sighand_exec();
603 /*
604 * We do not test reader's progress here, because we are mainly
605 * interested in writer's progress. The reader never blocks
606 * anyway. We have to test for reader/writer's progress
607 * separately, otherwise we could think the writer is doing
608 * progress when it's blocked by an always progressing reader.
609 */
610#ifdef READER_PROGRESS
611progress_reader:
612#endif
613 urcu_one_read_sig(i, j, nest_i, tmp, tmp2);
614 od;
615}
616
617#endif
618
619/* Model the RCU update process. */
620
621active proctype urcu_writer()
622{
623 byte i, j;
624 byte tmp, tmp2;
625 byte old_gen;
626
627 wait_init_done();
628
629 assert(get_pid() < NR_PROCS);
630
631 do
632 :: (READ_CACHED_VAR(generation_ptr) < 5) ->
633#ifdef WRITER_PROGRESS
634progress_writer1:
635#endif
636 ooo_mem(i);
637 dispatch_sighand_write_exec();
638 atomic {
639 old_gen = READ_CACHED_VAR(generation_ptr);
640 WRITE_CACHED_VAR(generation_ptr, old_gen + 1);
641 }
642 ooo_mem(i);
643 dispatch_sighand_write_exec();
644
645 do
646 :: 1 ->
647 atomic {
648 if
649 :: write_lock == 0 ->
650 write_lock = 1;
651 break;
652 :: else ->
653 skip;
654 fi;
655 }
656 od;
657 smp_mb_writer(i, j);
658 dispatch_sighand_write_exec();
659 tmp = READ_CACHED_VAR(urcu_gp_ctr);
660 ooo_mem(i);
661 dispatch_sighand_write_exec();
662 WRITE_CACHED_VAR(urcu_gp_ctr, tmp ^ RCU_GP_CTR_BIT);
663 ooo_mem(i);
664 dispatch_sighand_write_exec();
665 //smp_mc(i);
666 wait_for_quiescent_state(tmp, tmp2, i, j);
667 //smp_mc(i);
668#ifndef SINGLE_FLIP
669 ooo_mem(i);
670 dispatch_sighand_write_exec();
671 tmp = READ_CACHED_VAR(urcu_gp_ctr);
672 ooo_mem(i);
673 dispatch_sighand_write_exec();
674 WRITE_CACHED_VAR(urcu_gp_ctr, tmp ^ RCU_GP_CTR_BIT);
675 //smp_mc(i);
676 ooo_mem(i);
677 dispatch_sighand_write_exec();
678 wait_for_quiescent_state(tmp, tmp2, i, j);
679#endif
680 smp_mb_writer(i, j);
681 dispatch_sighand_write_exec();
682 write_lock = 0;
683 /* free-up step, e.g., kfree(). */
684 atomic {
685 last_free_gen = old_gen;
686 free_done = 1;
687 }
688 :: else -> break;
689 od;
690 /*
691 * Given the reader loops infinitely, let the writer also busy-loop
692 * with progress here so, with weak fairness, we can test the
693 * writer's progress.
694 */
695end_writer:
696 do
697 :: 1 ->
698#ifdef WRITER_PROGRESS
699progress_writer2:
700#endif
701 dispatch_sighand_write_exec();
702 od;
703}
704
705/* Leave after the readers and writers so the pid count is ok. */
706init {
707 byte i, j;
708
709 atomic {
710 INIT_CACHED_VAR(urcu_gp_ctr, 1, j);
711 INIT_CACHED_VAR(generation_ptr, 0, j);
712
713 i = 0;
714 do
715 :: i < NR_READERS ->
716 INIT_CACHED_VAR(urcu_active_readers[i], 0, j);
717 read_generation[i] = 1;
718 data_access[i] = 0;
719 i++;
720 :: i >= NR_READERS -> break
721 od;
722 init_done = 1;
723 }
724}
This page took 0.047815 seconds and 4 git commands to generate.