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)
34
# if !defined N_CYCLES || N_CYCLES <= 1 || defined TEST_EXPENSIVE
36
# warning defaulting to 2 concurrent exclusive sections
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
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)