2 * This model describes the implementation of exclusive sections in
3 * cpus-common.c (start_exclusive, end_exclusive, cpu_exec_start,
8 * This file is in the public domain. If you really want a license,
12 * spin -a docs/tcg-exclusive.promela
16 * Tunable processor macros: N_CPUS, N_EXCLUSIVE, N_CYCLES, TEST_EXPENSIVE.
19 // Define the missing parameters for the model
22 #warning defaulting to 2 CPU processes
25 // the expensive test is not so expensive for <= 3 CPUs
27 #define TEST_EXPENSIVE
31 # if !defined N_CYCLES || N_CYCLES <= 1 || defined TEST_EXPENSIVE
32 # define N_EXCLUSIVE 2
33 # warning defaulting to 2 concurrent exclusive sections
35 # define N_EXCLUSIVE 1
36 # warning defaulting to 1 concurrent exclusive sections
40 # if N_EXCLUSIVE <= 1 || defined TEST_EXPENSIVE
42 # warning defaulting to 2 CPU cycles
45 # warning defaulting to 1 CPU cycles
50 // synchronization primitives. condition variables require a
51 // process-local "cond_t saved;" variable.
54 #define MUTEX_LOCK(m) atomic { m == 0 -> m = 1 }
55 #define MUTEX_UNLOCK(m) m = 0
58 #define COND_WAIT(c, m) { \
61 c != saved -> MUTEX_LOCK(m); \
63 #define COND_BROADCAST(c) c++
65 // this is the logic from cpus-common.c
68 cond_t exclusive_cond;
69 cond_t exclusive_resume;
73 byte has_waiter[N_CPUS];
75 #define exclusive_idle() \
77 :: pending_cpus -> COND_WAIT(exclusive_resume, mutex); \
81 #define start_exclusive() \
90 :: running[i] -> has_waiter[i] = 1; pending_cpus++; \
99 :: pending_cpus > 1 -> COND_WAIT(exclusive_cond, mutex); \
103 #define end_exclusive() \
105 COND_BROADCAST(exclusive_resume); \
108 #define cpu_exec_start(id) \
114 #define cpu_exec_end(id) \
118 :: pending_cpus -> { \
121 :: pending_cpus == 1 -> COND_BROADCAST(exclusive_cond); \
134 active[N_CPUS] proctype cpu()
136 byte id = _pid % N_CPUS;
141 :: cycles == N_CYCLES -> break;
155 active[N_EXCLUSIVE] proctype exclusive()
167 #define LIVENESS (done_cpu == N_CPUS * N_CYCLES && done_exclusive == N_EXCLUSIVE)
168 #define SAFETY !(in_exclusive && in_cpu)
170 never { /* ! ([] SAFETY && <> [] LIVENESS) */
172 // once the liveness property is satisfied, this is not executable
173 // and the never clause is not accepted
174 :: ! LIVENESS -> accept_liveness: skip
175 :: 1 -> assert(SAFETY)