lockcnt.c (11936B)
1/* 2 * QemuLockCnt implementation 3 * 4 * Copyright Red Hat, Inc. 2017 5 * 6 * Author: 7 * Paolo Bonzini <pbonzini@redhat.com> 8 */ 9#include "qemu/osdep.h" 10#include "qemu/thread.h" 11#include "qemu/atomic.h" 12#include "trace.h" 13 14#ifdef CONFIG_LINUX 15#include "qemu/futex.h" 16 17/* On Linux, bits 0-1 are a futex-based lock, bits 2-31 are the counter. 18 * For the mutex algorithm see Ulrich Drepper's "Futexes Are Tricky" (ok, 19 * this is not the most relaxing citation I could make...). It is similar 20 * to mutex2 in the paper. 21 */ 22 23#define QEMU_LOCKCNT_STATE_MASK 3 24#define QEMU_LOCKCNT_STATE_FREE 0 /* free, uncontended */ 25#define QEMU_LOCKCNT_STATE_LOCKED 1 /* locked, uncontended */ 26#define QEMU_LOCKCNT_STATE_WAITING 2 /* locked, contended */ 27 28#define QEMU_LOCKCNT_COUNT_STEP 4 29#define QEMU_LOCKCNT_COUNT_SHIFT 2 30 31void qemu_lockcnt_init(QemuLockCnt *lockcnt) 32{ 33 lockcnt->count = 0; 34} 35 36void qemu_lockcnt_destroy(QemuLockCnt *lockcnt) 37{ 38} 39 40/* *val is the current value of lockcnt->count. 41 * 42 * If the lock is free, try a cmpxchg from *val to new_if_free; return 43 * true and set *val to the old value found by the cmpxchg in 44 * lockcnt->count. 45 * 46 * If the lock is taken, wait for it to be released and return false 47 * *without trying again to take the lock*. Again, set *val to the 48 * new value of lockcnt->count. 49 * 50 * If *waited is true on return, new_if_free's bottom two bits must not 51 * be QEMU_LOCKCNT_STATE_LOCKED on subsequent calls, because the caller 52 * does not know if there are other waiters. Furthermore, after *waited 53 * is set the caller has effectively acquired the lock. If it returns 54 * with the lock not taken, it must wake another futex waiter. 55 */ 56static bool qemu_lockcnt_cmpxchg_or_wait(QemuLockCnt *lockcnt, int *val, 57 int new_if_free, bool *waited) 58{ 59 /* Fast path for when the lock is free. */ 60 if ((*val & QEMU_LOCKCNT_STATE_MASK) == QEMU_LOCKCNT_STATE_FREE) { 61 int expected = *val; 62 63 trace_lockcnt_fast_path_attempt(lockcnt, expected, new_if_free); 64 *val = qatomic_cmpxchg(&lockcnt->count, expected, new_if_free); 65 if (*val == expected) { 66 trace_lockcnt_fast_path_success(lockcnt, expected, new_if_free); 67 *val = new_if_free; 68 return true; 69 } 70 } 71 72 /* The slow path moves from locked to waiting if necessary, then 73 * does a futex wait. Both steps can be repeated ad nauseam, 74 * only getting out of the loop if we can have another shot at the 75 * fast path. Once we can, get out to compute the new destination 76 * value for the fast path. 77 */ 78 while ((*val & QEMU_LOCKCNT_STATE_MASK) != QEMU_LOCKCNT_STATE_FREE) { 79 if ((*val & QEMU_LOCKCNT_STATE_MASK) == QEMU_LOCKCNT_STATE_LOCKED) { 80 int expected = *val; 81 int new = expected - QEMU_LOCKCNT_STATE_LOCKED + QEMU_LOCKCNT_STATE_WAITING; 82 83 trace_lockcnt_futex_wait_prepare(lockcnt, expected, new); 84 *val = qatomic_cmpxchg(&lockcnt->count, expected, new); 85 if (*val == expected) { 86 *val = new; 87 } 88 continue; 89 } 90 91 if ((*val & QEMU_LOCKCNT_STATE_MASK) == QEMU_LOCKCNT_STATE_WAITING) { 92 *waited = true; 93 trace_lockcnt_futex_wait(lockcnt, *val); 94 qemu_futex_wait(&lockcnt->count, *val); 95 *val = qatomic_read(&lockcnt->count); 96 trace_lockcnt_futex_wait_resume(lockcnt, *val); 97 continue; 98 } 99 100 abort(); 101 } 102 return false; 103} 104 105static void lockcnt_wake(QemuLockCnt *lockcnt) 106{ 107 trace_lockcnt_futex_wake(lockcnt); 108 qemu_futex_wake(&lockcnt->count, 1); 109} 110 111void qemu_lockcnt_inc(QemuLockCnt *lockcnt) 112{ 113 int val = qatomic_read(&lockcnt->count); 114 bool waited = false; 115 116 for (;;) { 117 if (val >= QEMU_LOCKCNT_COUNT_STEP) { 118 int expected = val; 119 val = qatomic_cmpxchg(&lockcnt->count, val, 120 val + QEMU_LOCKCNT_COUNT_STEP); 121 if (val == expected) { 122 break; 123 } 124 } else { 125 /* The fast path is (0, unlocked)->(1, unlocked). */ 126 if (qemu_lockcnt_cmpxchg_or_wait(lockcnt, &val, QEMU_LOCKCNT_COUNT_STEP, 127 &waited)) { 128 break; 129 } 130 } 131 } 132 133 /* If we were woken by another thread, we should also wake one because 134 * we are effectively releasing the lock that was given to us. This is 135 * the case where qemu_lockcnt_lock would leave QEMU_LOCKCNT_STATE_WAITING 136 * in the low bits, and qemu_lockcnt_inc_and_unlock would find it and 137 * wake someone. 138 */ 139 if (waited) { 140 lockcnt_wake(lockcnt); 141 } 142} 143 144void qemu_lockcnt_dec(QemuLockCnt *lockcnt) 145{ 146 qatomic_sub(&lockcnt->count, QEMU_LOCKCNT_COUNT_STEP); 147} 148 149/* Decrement a counter, and return locked if it is decremented to zero. 150 * If the function returns true, it is impossible for the counter to 151 * become nonzero until the next qemu_lockcnt_unlock. 152 */ 153bool qemu_lockcnt_dec_and_lock(QemuLockCnt *lockcnt) 154{ 155 int val = qatomic_read(&lockcnt->count); 156 int locked_state = QEMU_LOCKCNT_STATE_LOCKED; 157 bool waited = false; 158 159 for (;;) { 160 if (val >= 2 * QEMU_LOCKCNT_COUNT_STEP) { 161 int expected = val; 162 val = qatomic_cmpxchg(&lockcnt->count, val, 163 val - QEMU_LOCKCNT_COUNT_STEP); 164 if (val == expected) { 165 break; 166 } 167 } else { 168 /* If count is going 1->0, take the lock. The fast path is 169 * (1, unlocked)->(0, locked) or (1, unlocked)->(0, waiting). 170 */ 171 if (qemu_lockcnt_cmpxchg_or_wait(lockcnt, &val, locked_state, &waited)) { 172 return true; 173 } 174 175 if (waited) { 176 /* At this point we do not know if there are more waiters. Assume 177 * there are. 178 */ 179 locked_state = QEMU_LOCKCNT_STATE_WAITING; 180 } 181 } 182 } 183 184 /* If we were woken by another thread, but we're returning in unlocked 185 * state, we should also wake a thread because we are effectively 186 * releasing the lock that was given to us. This is the case where 187 * qemu_lockcnt_lock would leave QEMU_LOCKCNT_STATE_WAITING in the low 188 * bits, and qemu_lockcnt_unlock would find it and wake someone. 189 */ 190 if (waited) { 191 lockcnt_wake(lockcnt); 192 } 193 return false; 194} 195 196/* If the counter is one, decrement it and return locked. Otherwise do 197 * nothing. 198 * 199 * If the function returns true, it is impossible for the counter to 200 * become nonzero until the next qemu_lockcnt_unlock. 201 */ 202bool qemu_lockcnt_dec_if_lock(QemuLockCnt *lockcnt) 203{ 204 int val = qatomic_read(&lockcnt->count); 205 int locked_state = QEMU_LOCKCNT_STATE_LOCKED; 206 bool waited = false; 207 208 while (val < 2 * QEMU_LOCKCNT_COUNT_STEP) { 209 /* If count is going 1->0, take the lock. The fast path is 210 * (1, unlocked)->(0, locked) or (1, unlocked)->(0, waiting). 211 */ 212 if (qemu_lockcnt_cmpxchg_or_wait(lockcnt, &val, locked_state, &waited)) { 213 return true; 214 } 215 216 if (waited) { 217 /* At this point we do not know if there are more waiters. Assume 218 * there are. 219 */ 220 locked_state = QEMU_LOCKCNT_STATE_WAITING; 221 } 222 } 223 224 /* If we were woken by another thread, but we're returning in unlocked 225 * state, we should also wake a thread because we are effectively 226 * releasing the lock that was given to us. This is the case where 227 * qemu_lockcnt_lock would leave QEMU_LOCKCNT_STATE_WAITING in the low 228 * bits, and qemu_lockcnt_inc_and_unlock would find it and wake someone. 229 */ 230 if (waited) { 231 lockcnt_wake(lockcnt); 232 } 233 return false; 234} 235 236void qemu_lockcnt_lock(QemuLockCnt *lockcnt) 237{ 238 int val = qatomic_read(&lockcnt->count); 239 int step = QEMU_LOCKCNT_STATE_LOCKED; 240 bool waited = false; 241 242 /* The third argument is only used if the low bits of val are 0 243 * (QEMU_LOCKCNT_STATE_FREE), so just blindly mix in the desired 244 * state. 245 */ 246 while (!qemu_lockcnt_cmpxchg_or_wait(lockcnt, &val, val + step, &waited)) { 247 if (waited) { 248 /* At this point we do not know if there are more waiters. Assume 249 * there are. 250 */ 251 step = QEMU_LOCKCNT_STATE_WAITING; 252 } 253 } 254} 255 256void qemu_lockcnt_inc_and_unlock(QemuLockCnt *lockcnt) 257{ 258 int expected, new, val; 259 260 val = qatomic_read(&lockcnt->count); 261 do { 262 expected = val; 263 new = (val + QEMU_LOCKCNT_COUNT_STEP) & ~QEMU_LOCKCNT_STATE_MASK; 264 trace_lockcnt_unlock_attempt(lockcnt, val, new); 265 val = qatomic_cmpxchg(&lockcnt->count, val, new); 266 } while (val != expected); 267 268 trace_lockcnt_unlock_success(lockcnt, val, new); 269 if (val & QEMU_LOCKCNT_STATE_WAITING) { 270 lockcnt_wake(lockcnt); 271 } 272} 273 274void qemu_lockcnt_unlock(QemuLockCnt *lockcnt) 275{ 276 int expected, new, val; 277 278 val = qatomic_read(&lockcnt->count); 279 do { 280 expected = val; 281 new = val & ~QEMU_LOCKCNT_STATE_MASK; 282 trace_lockcnt_unlock_attempt(lockcnt, val, new); 283 val = qatomic_cmpxchg(&lockcnt->count, val, new); 284 } while (val != expected); 285 286 trace_lockcnt_unlock_success(lockcnt, val, new); 287 if (val & QEMU_LOCKCNT_STATE_WAITING) { 288 lockcnt_wake(lockcnt); 289 } 290} 291 292unsigned qemu_lockcnt_count(QemuLockCnt *lockcnt) 293{ 294 return qatomic_read(&lockcnt->count) >> QEMU_LOCKCNT_COUNT_SHIFT; 295} 296#else 297void qemu_lockcnt_init(QemuLockCnt *lockcnt) 298{ 299 qemu_mutex_init(&lockcnt->mutex); 300 lockcnt->count = 0; 301} 302 303void qemu_lockcnt_destroy(QemuLockCnt *lockcnt) 304{ 305 qemu_mutex_destroy(&lockcnt->mutex); 306} 307 308void qemu_lockcnt_inc(QemuLockCnt *lockcnt) 309{ 310 int old; 311 for (;;) { 312 old = qatomic_read(&lockcnt->count); 313 if (old == 0) { 314 qemu_lockcnt_lock(lockcnt); 315 qemu_lockcnt_inc_and_unlock(lockcnt); 316 return; 317 } else { 318 if (qatomic_cmpxchg(&lockcnt->count, old, old + 1) == old) { 319 return; 320 } 321 } 322 } 323} 324 325void qemu_lockcnt_dec(QemuLockCnt *lockcnt) 326{ 327 qatomic_dec(&lockcnt->count); 328} 329 330/* Decrement a counter, and return locked if it is decremented to zero. 331 * It is impossible for the counter to become nonzero while the mutex 332 * is taken. 333 */ 334bool qemu_lockcnt_dec_and_lock(QemuLockCnt *lockcnt) 335{ 336 int val = qatomic_read(&lockcnt->count); 337 while (val > 1) { 338 int old = qatomic_cmpxchg(&lockcnt->count, val, val - 1); 339 if (old != val) { 340 val = old; 341 continue; 342 } 343 344 return false; 345 } 346 347 qemu_lockcnt_lock(lockcnt); 348 if (qatomic_fetch_dec(&lockcnt->count) == 1) { 349 return true; 350 } 351 352 qemu_lockcnt_unlock(lockcnt); 353 return false; 354} 355 356/* Decrement a counter and return locked if it is decremented to zero. 357 * Otherwise do nothing. 358 * 359 * It is impossible for the counter to become nonzero while the mutex 360 * is taken. 361 */ 362bool qemu_lockcnt_dec_if_lock(QemuLockCnt *lockcnt) 363{ 364 /* No need for acquire semantics if we return false. */ 365 int val = qatomic_read(&lockcnt->count); 366 if (val > 1) { 367 return false; 368 } 369 370 qemu_lockcnt_lock(lockcnt); 371 if (qatomic_fetch_dec(&lockcnt->count) == 1) { 372 return true; 373 } 374 375 qemu_lockcnt_inc_and_unlock(lockcnt); 376 return false; 377} 378 379void qemu_lockcnt_lock(QemuLockCnt *lockcnt) 380{ 381 qemu_mutex_lock(&lockcnt->mutex); 382} 383 384void qemu_lockcnt_inc_and_unlock(QemuLockCnt *lockcnt) 385{ 386 qatomic_inc(&lockcnt->count); 387 qemu_mutex_unlock(&lockcnt->mutex); 388} 389 390void qemu_lockcnt_unlock(QemuLockCnt *lockcnt) 391{ 392 qemu_mutex_unlock(&lockcnt->mutex); 393} 394 395unsigned qemu_lockcnt_count(QemuLockCnt *lockcnt) 396{ 397 return qatomic_read(&lockcnt->count); 398} 399#endif