qemu-thread: optimize QemuLockCnt with futexes on Linux

This is complex, but I think it is reasonably documented in the source.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Fam Zheng <famz@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-id: 20170112180800.21085-5-pbonzini@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Paolo Bonzini 2017-01-12 19:07:54 +01:00 committed by Stefan Hajnoczi
parent d7c99a1282
commit fbcc3e5004
7 changed files with 342 additions and 35 deletions

View file

@ -11,10 +11,6 @@
*
*/
#include "qemu/osdep.h"
#ifdef __linux__
#include <sys/syscall.h>
#include <linux/futex.h>
#endif
#include "qemu/thread.h"
#include "qemu/atomic.h"
#include "qemu/notify.h"
@ -294,28 +290,9 @@ void qemu_sem_wait(QemuSemaphore *sem)
}
#ifdef __linux__
#define futex(...) syscall(__NR_futex, __VA_ARGS__)
static inline void futex_wake(QemuEvent *ev, int n)
{
futex(ev, FUTEX_WAKE, n, NULL, NULL, 0);
}
static inline void futex_wait(QemuEvent *ev, unsigned val)
{
while (futex(ev, FUTEX_WAIT, (int) val, NULL, NULL, 0)) {
switch (errno) {
case EWOULDBLOCK:
return;
case EINTR:
break; /* get out of switch and retry */
default:
abort();
}
}
}
#include "qemu/futex.h"
#else
static inline void futex_wake(QemuEvent *ev, int n)
static inline void qemu_futex_wake(QemuEvent *ev, int n)
{
pthread_mutex_lock(&ev->lock);
if (n == 1) {
@ -326,7 +303,7 @@ static inline void futex_wake(QemuEvent *ev, int n)
pthread_mutex_unlock(&ev->lock);
}
static inline void futex_wait(QemuEvent *ev, unsigned val)
static inline void qemu_futex_wait(QemuEvent *ev, unsigned val)
{
pthread_mutex_lock(&ev->lock);
if (ev->value == val) {
@ -338,7 +315,7 @@ static inline void futex_wait(QemuEvent *ev, unsigned val)
/* Valid transitions:
* - free->set, when setting the event
* - busy->set, when setting the event, followed by futex_wake
* - busy->set, when setting the event, followed by qemu_futex_wake
* - set->free, when resetting the event
* - free->busy, when waiting
*
@ -381,7 +358,7 @@ void qemu_event_set(QemuEvent *ev)
if (atomic_read(&ev->value) != EV_SET) {
if (atomic_xchg(&ev->value, EV_SET) == EV_BUSY) {
/* There were waiters, wake them up. */
futex_wake(ev, INT_MAX);
qemu_futex_wake(ev, INT_MAX);
}
}
}
@ -419,7 +396,7 @@ void qemu_event_wait(QemuEvent *ev)
return;
}
}
futex_wait(ev, EV_BUSY);
qemu_futex_wait(ev, EV_BUSY);
}
}