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