2 * This model describes the implementation of exclusive sections in
3 * cpus-common.c (start_exclusive, end_exclusive, cpu_exec_start,
6 * Author: Paolo Bonzini <pbonzini@redhat.com>
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, USE_MUTEX,
20 // Define the missing parameters for the model
23 #warning defaulting to 2 CPU processes
26 // the expensive test is not so expensive for <= 2 CPUs
27 // If the mutex is used, it's also cheap (300 MB / 4 seconds) for 3 CPUs
28 // For 3 CPUs and the lock-free option it needs 1.5 GB of RAM
29 #if N_CPUS <= 2 || (N_CPUS <= 3 && defined USE_MUTEX)
30 #define TEST_EXPENSIVE
34 # if !defined N_CYCLES || N_CYCLES <= 1 || defined TEST_EXPENSIVE
35 # define N_EXCLUSIVE 2
36 # warning defaulting to 2 concurrent exclusive sections
38 # define N_EXCLUSIVE 1
39 # warning defaulting to 1 concurrent exclusive sections
43 # if N_EXCLUSIVE <= 1 || defined TEST_EXPENSIVE
45 # warning defaulting to 2 CPU cycles
48 # warning defaulting to 1 CPU cycles
53 // synchronization primitives. condition variables require a
54 // process-local "cond_t saved;" variable.
57 #define MUTEX_LOCK(m) atomic { m == 0 -> m = 1 }
58 #define MUTEX_UNLOCK(m) m = 0
61 #define COND_WAIT(c, m) { \
64 c != saved -> MUTEX_LOCK(m); \
66 #define COND_BROADCAST(c) c++
68 // this is the logic from cpus-common.c
71 cond_t exclusive_cond;
72 cond_t exclusive_resume;
76 byte has_waiter[N_CPUS];
78 #define exclusive_idle() \
80 :: pending_cpus -> COND_WAIT(exclusive_resume, mutex); \
84 #define start_exclusive() \
93 :: running[i] -> has_waiter[i] = 1; pending_cpus++; \
102 :: pending_cpus > 1 -> COND_WAIT(exclusive_cond, mutex); \
107 #define end_exclusive() \
110 COND_BROADCAST(exclusive_resume); \
114 // Simple version using mutexes
115 #define cpu_exec_start(id) \
121 #define cpu_exec_end(id) \
125 :: pending_cpus -> { \
128 :: pending_cpus == 1 -> COND_BROADCAST(exclusive_cond); \
136 // Wait-free fast path, only needs mutex when concurrent with
137 // an exclusive section
138 #define cpu_exec_start(id) \
141 :: pending_cpus -> { \
144 :: !has_waiter[id] -> { \
151 MUTEX_UNLOCK(mutex); \
156 #define cpu_exec_end(id) \
159 :: pending_cpus -> { \
162 :: has_waiter[id] -> { \
163 has_waiter[id] = 0; \
166 :: pending_cpus == 1 -> COND_BROADCAST(exclusive_cond); \
172 MUTEX_UNLOCK(mutex); \
182 active[N_CPUS] proctype cpu()
184 byte id = _pid % N_CPUS;
189 :: cycles == N_CYCLES -> break;
203 active[N_EXCLUSIVE] proctype exclusive()
215 #define LIVENESS (done_cpu == N_CPUS * N_CYCLES && done_exclusive == N_EXCLUSIVE)
216 #define SAFETY !(in_exclusive && in_cpu)
218 never { /* ! ([] SAFETY && <> [] LIVENESS) */
220 // once the liveness property is satisfied, this is not executable
221 // and the never clause is not accepted
222 :: ! LIVENESS -> accept_liveness: skip
223 :: 1 -> assert(SAFETY)