Merge tag 'pull-target-arm-20231219' of https://git.linaro.org/people/pmaydell/qemu...
[qemu/ar7.git] / util / lockcnt.c
blob5da36946b1b6deb90621f4d64378586c6c8c2670
1 /*
2 * QemuLockCnt implementation
4 * Copyright Red Hat, Inc. 2017
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"
14 #ifdef CONFIG_LINUX
15 #include "qemu/futex.h"
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.
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 */
28 #define QEMU_LOCKCNT_COUNT_STEP 4
29 #define QEMU_LOCKCNT_COUNT_SHIFT 2
31 void qemu_lockcnt_init(QemuLockCnt *lockcnt)
33 lockcnt->count = 0;
36 void qemu_lockcnt_destroy(QemuLockCnt *lockcnt)
40 /* *val is the current value of lockcnt->count.
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.
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.
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.
56 static bool qemu_lockcnt_cmpxchg_or_wait(QemuLockCnt *lockcnt, int *val,
57 int new_if_free, bool *waited)
59 /* Fast path for when the lock is free. */
60 if ((*val & QEMU_LOCKCNT_STATE_MASK) == QEMU_LOCKCNT_STATE_FREE) {
61 int expected = *val;
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;
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.
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;
83 trace_lockcnt_futex_wait_prepare(lockcnt, expected, new);
84 *val = qatomic_cmpxchg(&lockcnt->count, expected, new);
85 if (*val == expected) {
86 *val = new;
88 continue;
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;
100 abort();
102 return false;
105 static void lockcnt_wake(QemuLockCnt *lockcnt)
107 trace_lockcnt_futex_wake(lockcnt);
108 qemu_futex_wake(&lockcnt->count, 1);
111 void qemu_lockcnt_inc(QemuLockCnt *lockcnt)
113 int val = qatomic_read(&lockcnt->count);
114 bool waited = false;
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;
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;
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.
139 if (waited) {
140 lockcnt_wake(lockcnt);
144 void qemu_lockcnt_dec(QemuLockCnt *lockcnt)
146 qatomic_sub(&lockcnt->count, QEMU_LOCKCNT_COUNT_STEP);
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.
153 bool qemu_lockcnt_dec_and_lock(QemuLockCnt *lockcnt)
155 int val = qatomic_read(&lockcnt->count);
156 int locked_state = QEMU_LOCKCNT_STATE_LOCKED;
157 bool waited = false;
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;
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).
171 if (qemu_lockcnt_cmpxchg_or_wait(lockcnt, &val, locked_state, &waited)) {
172 return true;
175 if (waited) {
176 /* At this point we do not know if there are more waiters. Assume
177 * there are.
179 locked_state = QEMU_LOCKCNT_STATE_WAITING;
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.
190 if (waited) {
191 lockcnt_wake(lockcnt);
193 return false;
196 /* If the counter is one, decrement it and return locked. Otherwise do
197 * nothing.
199 * If the function returns true, it is impossible for the counter to
200 * become nonzero until the next qemu_lockcnt_unlock.
202 bool qemu_lockcnt_dec_if_lock(QemuLockCnt *lockcnt)
204 int val = qatomic_read(&lockcnt->count);
205 int locked_state = QEMU_LOCKCNT_STATE_LOCKED;
206 bool waited = false;
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).
212 if (qemu_lockcnt_cmpxchg_or_wait(lockcnt, &val, locked_state, &waited)) {
213 return true;
216 if (waited) {
217 /* At this point we do not know if there are more waiters. Assume
218 * there are.
220 locked_state = QEMU_LOCKCNT_STATE_WAITING;
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.
230 if (waited) {
231 lockcnt_wake(lockcnt);
233 return false;
236 void qemu_lockcnt_lock(QemuLockCnt *lockcnt)
238 int val = qatomic_read(&lockcnt->count);
239 int step = QEMU_LOCKCNT_STATE_LOCKED;
240 bool waited = false;
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.
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.
251 step = QEMU_LOCKCNT_STATE_WAITING;
256 void qemu_lockcnt_inc_and_unlock(QemuLockCnt *lockcnt)
258 int expected, new, val;
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);
268 trace_lockcnt_unlock_success(lockcnt, val, new);
269 if (val & QEMU_LOCKCNT_STATE_WAITING) {
270 lockcnt_wake(lockcnt);
274 void qemu_lockcnt_unlock(QemuLockCnt *lockcnt)
276 int expected, new, val;
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);
286 trace_lockcnt_unlock_success(lockcnt, val, new);
287 if (val & QEMU_LOCKCNT_STATE_WAITING) {
288 lockcnt_wake(lockcnt);
292 unsigned qemu_lockcnt_count(QemuLockCnt *lockcnt)
294 return qatomic_read(&lockcnt->count) >> QEMU_LOCKCNT_COUNT_SHIFT;
296 #else
297 void qemu_lockcnt_init(QemuLockCnt *lockcnt)
299 qemu_mutex_init(&lockcnt->mutex);
300 lockcnt->count = 0;
303 void qemu_lockcnt_destroy(QemuLockCnt *lockcnt)
305 qemu_mutex_destroy(&lockcnt->mutex);
308 void qemu_lockcnt_inc(QemuLockCnt *lockcnt)
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;
325 void qemu_lockcnt_dec(QemuLockCnt *lockcnt)
327 qatomic_dec(&lockcnt->count);
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.
334 bool qemu_lockcnt_dec_and_lock(QemuLockCnt *lockcnt)
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;
344 return false;
347 qemu_lockcnt_lock(lockcnt);
348 if (qatomic_fetch_dec(&lockcnt->count) == 1) {
349 return true;
352 qemu_lockcnt_unlock(lockcnt);
353 return false;
356 /* Decrement a counter and return locked if it is decremented to zero.
357 * Otherwise do nothing.
359 * It is impossible for the counter to become nonzero while the mutex
360 * is taken.
362 bool qemu_lockcnt_dec_if_lock(QemuLockCnt *lockcnt)
364 /* No need for acquire semantics if we return false. */
365 int val = qatomic_read(&lockcnt->count);
366 if (val > 1) {
367 return false;
370 qemu_lockcnt_lock(lockcnt);
371 if (qatomic_fetch_dec(&lockcnt->count) == 1) {
372 return true;
375 qemu_lockcnt_inc_and_unlock(lockcnt);
376 return false;
379 void qemu_lockcnt_lock(QemuLockCnt *lockcnt)
381 qemu_mutex_lock(&lockcnt->mutex);
384 void qemu_lockcnt_inc_and_unlock(QemuLockCnt *lockcnt)
386 qatomic_inc(&lockcnt->count);
387 qemu_mutex_unlock(&lockcnt->mutex);
390 void qemu_lockcnt_unlock(QemuLockCnt *lockcnt)
392 qemu_mutex_unlock(&lockcnt->mutex);
395 unsigned qemu_lockcnt_count(QemuLockCnt *lockcnt)
397 return qatomic_read(&lockcnt->count);
399 #endif