diff options
Diffstat (limited to 'util/qemu-thread-posix.c')
| -rw-r--r-- | util/qemu-thread-posix.c | 170 |
1 files changed, 0 insertions, 170 deletions
diff --git a/util/qemu-thread-posix.c b/util/qemu-thread-posix.c index 7fafbedbc4..ba725444ba 100644 --- a/util/qemu-thread-posix.c +++ b/util/qemu-thread-posix.c @@ -317,176 +317,6 @@ void qemu_sem_wait(QemuSemaphore *sem) qemu_mutex_unlock(&sem->mutex); } -#ifdef CONFIG_LINUX -#include "qemu/futex.h" -#endif - -/* Valid transitions: - * - FREE -> SET (qemu_event_set) - * - BUSY -> SET (qemu_event_set) - * - SET -> FREE (qemu_event_reset) - * - FREE -> BUSY (qemu_event_wait) - * - * With futex, the waking and blocking operations follow - * BUSY -> SET and FREE -> BUSY, respectively. - * - * Without futex, BUSY -> SET and FREE -> BUSY never happen. Instead, the waking - * operation follows FREE -> SET and the blocking operation will happen in - * qemu_event_wait() if the event is not SET. - * - * SET->BUSY does not happen (it can be observed from the outside but - * it really is SET->FREE->BUSY). - * - * busy->free provably cannot happen; to enforce it, the set->free transition - * is done with an OR, which becomes a no-op if the event has concurrently - * transitioned to free or busy. - */ - -#define EV_SET 0 -#define EV_FREE 1 -#define EV_BUSY -1 - -void qemu_event_init(QemuEvent *ev, bool init) -{ -#ifndef CONFIG_LINUX - pthread_mutex_init(&ev->lock, NULL); - pthread_cond_init(&ev->cond, NULL); -#endif - - ev->value = (init ? EV_SET : EV_FREE); - ev->initialized = true; -} - -void qemu_event_destroy(QemuEvent *ev) -{ - assert(ev->initialized); - ev->initialized = false; -#ifndef CONFIG_LINUX - pthread_mutex_destroy(&ev->lock); - pthread_cond_destroy(&ev->cond); -#endif -} - -void qemu_event_set(QemuEvent *ev) -{ - assert(ev->initialized); - -#ifdef CONFIG_LINUX - /* - * Pairs with both qemu_event_reset() and qemu_event_wait(). - * - * qemu_event_set has release semantics, but because it *loads* - * ev->value we need a full memory barrier here. - */ - smp_mb(); - if (qatomic_read(&ev->value) != EV_SET) { - int old = qatomic_xchg(&ev->value, EV_SET); - - /* Pairs with memory barrier in kernel futex_wait system call. */ - smp_mb__after_rmw(); - if (old == EV_BUSY) { - /* There were waiters, wake them up. */ - qemu_futex_wake_all(ev); - } - } -#else - pthread_mutex_lock(&ev->lock); - /* Pairs with qemu_event_reset()'s load acquire. */ - qatomic_store_release(&ev->value, EV_SET); - pthread_cond_broadcast(&ev->cond); - pthread_mutex_unlock(&ev->lock); -#endif -} - -void qemu_event_reset(QemuEvent *ev) -{ - assert(ev->initialized); - -#ifdef CONFIG_LINUX - /* - * If there was a concurrent reset (or even reset+wait), - * do nothing. Otherwise change EV_SET->EV_FREE. - */ - qatomic_or(&ev->value, EV_FREE); - - /* - * Order reset before checking the condition in the caller. - * Pairs with the first memory barrier in qemu_event_set(). - */ - smp_mb__after_rmw(); -#else - /* - * If futexes are not available, there are no EV_FREE->EV_BUSY - * transitions because wakeups are done entirely through the - * condition variable. Since qatomic_set() only writes EV_FREE, - * the load seems useless but in reality, the acquire synchronizes - * with qemu_event_set()'s store release: if qemu_event_reset() - * sees EV_SET here, then the caller will certainly see a - * successful condition and skip qemu_event_wait(): - * - * done = 1; if (done == 0) - * qemu_event_set() { qemu_event_reset() { - * lock(); - * ev->value = EV_SET -----> load ev->value - * ev->value = old value | EV_FREE - * cond_broadcast() - * unlock(); } - * } if (done == 0) - * // qemu_event_wait() not called - */ - qatomic_set(&ev->value, qatomic_load_acquire(&ev->value) | EV_FREE); -#endif -} - -void qemu_event_wait(QemuEvent *ev) -{ - assert(ev->initialized); - -#ifdef CONFIG_LINUX - while (true) { - /* - * qemu_event_wait must synchronize with qemu_event_set even if it does - * not go down the slow path, so this load-acquire is needed that - * synchronizes with the first memory barrier in qemu_event_set(). - */ - unsigned value = qatomic_load_acquire(&ev->value); - if (value == EV_SET) { - break; - } - - if (value == EV_FREE) { - /* - * Leave the event reset and tell qemu_event_set that there are - * waiters. No need to retry, because there cannot be a concurrent - * busy->free transition. After the CAS, the event will be either - * set or busy. - * - * This cmpxchg doesn't have particular ordering requirements if it - * succeeds (moving the store earlier can only cause qemu_event_set() - * to issue _more_ wakeups), the failing case needs acquire semantics - * like the load above. - */ - if (qatomic_cmpxchg(&ev->value, EV_FREE, EV_BUSY) == EV_SET) { - break; - } - } - - /* - * This is the final check for a concurrent set, so it does need - * a smp_mb() pairing with the second barrier of qemu_event_set(). - * The barrier is inside the FUTEX_WAIT system call. - */ - qemu_futex_wait(ev, EV_BUSY); - } -#else - pthread_mutex_lock(&ev->lock); - while (qatomic_read(&ev->value) != EV_SET) { - pthread_cond_wait(&ev->cond, &ev->lock); - } - pthread_mutex_unlock(&ev->lock); -#endif -} - static __thread NotifierList thread_exit; /* |