1*ac06724aSPaolo Bonzini/* 2*ac06724aSPaolo Bonzini * This model describes the implementation of exclusive sections in 3*ac06724aSPaolo Bonzini * cpus-common.c (start_exclusive, end_exclusive, cpu_exec_start, 4*ac06724aSPaolo Bonzini * cpu_exec_end). 5*ac06724aSPaolo Bonzini * 6*ac06724aSPaolo Bonzini * Author: Paolo Bonzini <pbonzini@redhat.com> 7*ac06724aSPaolo Bonzini * 8*ac06724aSPaolo Bonzini * This file is in the public domain. If you really want a license, 9*ac06724aSPaolo Bonzini * the WTFPL will do. 10*ac06724aSPaolo Bonzini * 11*ac06724aSPaolo Bonzini * To verify it: 12*ac06724aSPaolo Bonzini * spin -a docs/tcg-exclusive.promela 13*ac06724aSPaolo Bonzini * gcc pan.c -O2 14*ac06724aSPaolo Bonzini * ./a.out -a 15*ac06724aSPaolo Bonzini * 16*ac06724aSPaolo Bonzini * Tunable processor macros: N_CPUS, N_EXCLUSIVE, N_CYCLES, USE_MUTEX, 17*ac06724aSPaolo Bonzini * TEST_EXPENSIVE. 18*ac06724aSPaolo Bonzini */ 19*ac06724aSPaolo Bonzini 20*ac06724aSPaolo Bonzini// Define the missing parameters for the model 21*ac06724aSPaolo Bonzini#ifndef N_CPUS 22*ac06724aSPaolo Bonzini#define N_CPUS 2 23*ac06724aSPaolo Bonzini#warning defaulting to 2 CPU processes 24*ac06724aSPaolo Bonzini#endif 25*ac06724aSPaolo Bonzini 26*ac06724aSPaolo Bonzini// the expensive test is not so expensive for <= 2 CPUs 27*ac06724aSPaolo Bonzini// If the mutex is used, it's also cheap (300 MB / 4 seconds) for 3 CPUs 28*ac06724aSPaolo Bonzini// For 3 CPUs and the lock-free option it needs 1.5 GB of RAM 29*ac06724aSPaolo Bonzini#if N_CPUS <= 2 || (N_CPUS <= 3 && defined USE_MUTEX) 30*ac06724aSPaolo Bonzini#define TEST_EXPENSIVE 31*ac06724aSPaolo Bonzini#endif 32*ac06724aSPaolo Bonzini 33*ac06724aSPaolo Bonzini#ifndef N_EXCLUSIVE 34*ac06724aSPaolo Bonzini# if !defined N_CYCLES || N_CYCLES <= 1 || defined TEST_EXPENSIVE 35*ac06724aSPaolo Bonzini# define N_EXCLUSIVE 2 36*ac06724aSPaolo Bonzini# warning defaulting to 2 concurrent exclusive sections 37*ac06724aSPaolo Bonzini# else 38*ac06724aSPaolo Bonzini# define N_EXCLUSIVE 1 39*ac06724aSPaolo Bonzini# warning defaulting to 1 concurrent exclusive sections 40*ac06724aSPaolo Bonzini# endif 41*ac06724aSPaolo Bonzini#endif 42*ac06724aSPaolo Bonzini#ifndef N_CYCLES 43*ac06724aSPaolo Bonzini# if N_EXCLUSIVE <= 1 || defined TEST_EXPENSIVE 44*ac06724aSPaolo Bonzini# define N_CYCLES 2 45*ac06724aSPaolo Bonzini# warning defaulting to 2 CPU cycles 46*ac06724aSPaolo Bonzini# else 47*ac06724aSPaolo Bonzini# define N_CYCLES 1 48*ac06724aSPaolo Bonzini# warning defaulting to 1 CPU cycles 49*ac06724aSPaolo Bonzini# endif 50*ac06724aSPaolo Bonzini#endif 51*ac06724aSPaolo Bonzini 52*ac06724aSPaolo Bonzini 53*ac06724aSPaolo Bonzini// synchronization primitives. condition variables require a 54*ac06724aSPaolo Bonzini// process-local "cond_t saved;" variable. 55*ac06724aSPaolo Bonzini 56*ac06724aSPaolo Bonzini#define mutex_t byte 57*ac06724aSPaolo Bonzini#define MUTEX_LOCK(m) atomic { m == 0 -> m = 1 } 58*ac06724aSPaolo Bonzini#define MUTEX_UNLOCK(m) m = 0 59*ac06724aSPaolo Bonzini 60*ac06724aSPaolo Bonzini#define cond_t int 61*ac06724aSPaolo Bonzini#define COND_WAIT(c, m) { \ 62*ac06724aSPaolo Bonzini saved = c; \ 63*ac06724aSPaolo Bonzini MUTEX_UNLOCK(m); \ 64*ac06724aSPaolo Bonzini c != saved -> MUTEX_LOCK(m); \ 65*ac06724aSPaolo Bonzini } 66*ac06724aSPaolo Bonzini#define COND_BROADCAST(c) c++ 67*ac06724aSPaolo Bonzini 68*ac06724aSPaolo Bonzini// this is the logic from cpus-common.c 69*ac06724aSPaolo Bonzini 70*ac06724aSPaolo Bonzinimutex_t mutex; 71*ac06724aSPaolo Bonzinicond_t exclusive_cond; 72*ac06724aSPaolo Bonzinicond_t exclusive_resume; 73*ac06724aSPaolo Bonzinibyte pending_cpus; 74*ac06724aSPaolo Bonzini 75*ac06724aSPaolo Bonzinibyte running[N_CPUS]; 76*ac06724aSPaolo Bonzinibyte has_waiter[N_CPUS]; 77*ac06724aSPaolo Bonzini 78*ac06724aSPaolo Bonzini#define exclusive_idle() \ 79*ac06724aSPaolo Bonzini do \ 80*ac06724aSPaolo Bonzini :: pending_cpus -> COND_WAIT(exclusive_resume, mutex); \ 81*ac06724aSPaolo Bonzini :: else -> break; \ 82*ac06724aSPaolo Bonzini od 83*ac06724aSPaolo Bonzini 84*ac06724aSPaolo Bonzini#define start_exclusive() \ 85*ac06724aSPaolo Bonzini MUTEX_LOCK(mutex); \ 86*ac06724aSPaolo Bonzini exclusive_idle(); \ 87*ac06724aSPaolo Bonzini pending_cpus = 1; \ 88*ac06724aSPaolo Bonzini \ 89*ac06724aSPaolo Bonzini i = 0; \ 90*ac06724aSPaolo Bonzini do \ 91*ac06724aSPaolo Bonzini :: i < N_CPUS -> { \ 92*ac06724aSPaolo Bonzini if \ 93*ac06724aSPaolo Bonzini :: running[i] -> has_waiter[i] = 1; pending_cpus++; \ 94*ac06724aSPaolo Bonzini :: else -> skip; \ 95*ac06724aSPaolo Bonzini fi; \ 96*ac06724aSPaolo Bonzini i++; \ 97*ac06724aSPaolo Bonzini } \ 98*ac06724aSPaolo Bonzini :: else -> break; \ 99*ac06724aSPaolo Bonzini od; \ 100*ac06724aSPaolo Bonzini \ 101*ac06724aSPaolo Bonzini do \ 102*ac06724aSPaolo Bonzini :: pending_cpus > 1 -> COND_WAIT(exclusive_cond, mutex); \ 103*ac06724aSPaolo Bonzini :: else -> break; \ 104*ac06724aSPaolo Bonzini od; \ 105*ac06724aSPaolo Bonzini MUTEX_UNLOCK(mutex); 106*ac06724aSPaolo Bonzini 107*ac06724aSPaolo Bonzini#define end_exclusive() \ 108*ac06724aSPaolo Bonzini MUTEX_LOCK(mutex); \ 109*ac06724aSPaolo Bonzini pending_cpus = 0; \ 110*ac06724aSPaolo Bonzini COND_BROADCAST(exclusive_resume); \ 111*ac06724aSPaolo Bonzini MUTEX_UNLOCK(mutex); 112*ac06724aSPaolo Bonzini 113*ac06724aSPaolo Bonzini#ifdef USE_MUTEX 114*ac06724aSPaolo Bonzini// Simple version using mutexes 115*ac06724aSPaolo Bonzini#define cpu_exec_start(id) \ 116*ac06724aSPaolo Bonzini MUTEX_LOCK(mutex); \ 117*ac06724aSPaolo Bonzini exclusive_idle(); \ 118*ac06724aSPaolo Bonzini running[id] = 1; \ 119*ac06724aSPaolo Bonzini MUTEX_UNLOCK(mutex); 120*ac06724aSPaolo Bonzini 121*ac06724aSPaolo Bonzini#define cpu_exec_end(id) \ 122*ac06724aSPaolo Bonzini MUTEX_LOCK(mutex); \ 123*ac06724aSPaolo Bonzini running[id] = 0; \ 124*ac06724aSPaolo Bonzini if \ 125*ac06724aSPaolo Bonzini :: pending_cpus -> { \ 126*ac06724aSPaolo Bonzini pending_cpus--; \ 127*ac06724aSPaolo Bonzini if \ 128*ac06724aSPaolo Bonzini :: pending_cpus == 1 -> COND_BROADCAST(exclusive_cond); \ 129*ac06724aSPaolo Bonzini :: else -> skip; \ 130*ac06724aSPaolo Bonzini fi; \ 131*ac06724aSPaolo Bonzini } \ 132*ac06724aSPaolo Bonzini :: else -> skip; \ 133*ac06724aSPaolo Bonzini fi; \ 134*ac06724aSPaolo Bonzini MUTEX_UNLOCK(mutex); 135*ac06724aSPaolo Bonzini#else 136*ac06724aSPaolo Bonzini// Wait-free fast path, only needs mutex when concurrent with 137*ac06724aSPaolo Bonzini// an exclusive section 138*ac06724aSPaolo Bonzini#define cpu_exec_start(id) \ 139*ac06724aSPaolo Bonzini running[id] = 1; \ 140*ac06724aSPaolo Bonzini if \ 141*ac06724aSPaolo Bonzini :: pending_cpus -> { \ 142*ac06724aSPaolo Bonzini MUTEX_LOCK(mutex); \ 143*ac06724aSPaolo Bonzini if \ 144*ac06724aSPaolo Bonzini :: !has_waiter[id] -> { \ 145*ac06724aSPaolo Bonzini running[id] = 0; \ 146*ac06724aSPaolo Bonzini exclusive_idle(); \ 147*ac06724aSPaolo Bonzini running[id] = 1; \ 148*ac06724aSPaolo Bonzini } \ 149*ac06724aSPaolo Bonzini :: else -> skip; \ 150*ac06724aSPaolo Bonzini fi; \ 151*ac06724aSPaolo Bonzini MUTEX_UNLOCK(mutex); \ 152*ac06724aSPaolo Bonzini } \ 153*ac06724aSPaolo Bonzini :: else -> skip; \ 154*ac06724aSPaolo Bonzini fi; 155*ac06724aSPaolo Bonzini 156*ac06724aSPaolo Bonzini#define cpu_exec_end(id) \ 157*ac06724aSPaolo Bonzini running[id] = 0; \ 158*ac06724aSPaolo Bonzini if \ 159*ac06724aSPaolo Bonzini :: pending_cpus -> { \ 160*ac06724aSPaolo Bonzini MUTEX_LOCK(mutex); \ 161*ac06724aSPaolo Bonzini if \ 162*ac06724aSPaolo Bonzini :: has_waiter[id] -> { \ 163*ac06724aSPaolo Bonzini has_waiter[id] = 0; \ 164*ac06724aSPaolo Bonzini pending_cpus--; \ 165*ac06724aSPaolo Bonzini if \ 166*ac06724aSPaolo Bonzini :: pending_cpus == 1 -> COND_BROADCAST(exclusive_cond); \ 167*ac06724aSPaolo Bonzini :: else -> skip; \ 168*ac06724aSPaolo Bonzini fi; \ 169*ac06724aSPaolo Bonzini } \ 170*ac06724aSPaolo Bonzini :: else -> skip; \ 171*ac06724aSPaolo Bonzini fi; \ 172*ac06724aSPaolo Bonzini MUTEX_UNLOCK(mutex); \ 173*ac06724aSPaolo Bonzini } \ 174*ac06724aSPaolo Bonzini :: else -> skip; \ 175*ac06724aSPaolo Bonzini fi 176*ac06724aSPaolo Bonzini#endif 177*ac06724aSPaolo Bonzini 178*ac06724aSPaolo Bonzini// Promela processes 179*ac06724aSPaolo Bonzini 180*ac06724aSPaolo Bonzinibyte done_cpu; 181*ac06724aSPaolo Bonzinibyte in_cpu; 182*ac06724aSPaolo Bonziniactive[N_CPUS] proctype cpu() 183*ac06724aSPaolo Bonzini{ 184*ac06724aSPaolo Bonzini byte id = _pid % N_CPUS; 185*ac06724aSPaolo Bonzini byte cycles = 0; 186*ac06724aSPaolo Bonzini cond_t saved; 187*ac06724aSPaolo Bonzini 188*ac06724aSPaolo Bonzini do 189*ac06724aSPaolo Bonzini :: cycles == N_CYCLES -> break; 190*ac06724aSPaolo Bonzini :: else -> { 191*ac06724aSPaolo Bonzini cycles++; 192*ac06724aSPaolo Bonzini cpu_exec_start(id) 193*ac06724aSPaolo Bonzini in_cpu++; 194*ac06724aSPaolo Bonzini done_cpu++; 195*ac06724aSPaolo Bonzini in_cpu--; 196*ac06724aSPaolo Bonzini cpu_exec_end(id) 197*ac06724aSPaolo Bonzini } 198*ac06724aSPaolo Bonzini od; 199*ac06724aSPaolo Bonzini} 200*ac06724aSPaolo Bonzini 201*ac06724aSPaolo Bonzinibyte done_exclusive; 202*ac06724aSPaolo Bonzinibyte in_exclusive; 203*ac06724aSPaolo Bonziniactive[N_EXCLUSIVE] proctype exclusive() 204*ac06724aSPaolo Bonzini{ 205*ac06724aSPaolo Bonzini cond_t saved; 206*ac06724aSPaolo Bonzini byte i; 207*ac06724aSPaolo Bonzini 208*ac06724aSPaolo Bonzini start_exclusive(); 209*ac06724aSPaolo Bonzini in_exclusive = 1; 210*ac06724aSPaolo Bonzini done_exclusive++; 211*ac06724aSPaolo Bonzini in_exclusive = 0; 212*ac06724aSPaolo Bonzini end_exclusive(); 213*ac06724aSPaolo Bonzini} 214*ac06724aSPaolo Bonzini 215*ac06724aSPaolo Bonzini#define LIVENESS (done_cpu == N_CPUS * N_CYCLES && done_exclusive == N_EXCLUSIVE) 216*ac06724aSPaolo Bonzini#define SAFETY !(in_exclusive && in_cpu) 217*ac06724aSPaolo Bonzini 218*ac06724aSPaolo Bonzininever { /* ! ([] SAFETY && <> [] LIVENESS) */ 219*ac06724aSPaolo Bonzini do 220*ac06724aSPaolo Bonzini // once the liveness property is satisfied, this is not executable 221*ac06724aSPaolo Bonzini // and the never clause is not accepted 222*ac06724aSPaolo Bonzini :: ! LIVENESS -> accept_liveness: skip 223*ac06724aSPaolo Bonzini :: 1 -> assert(SAFETY) 224*ac06724aSPaolo Bonzini od; 225*ac06724aSPaolo Bonzini} 226