[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [RFC PATCH 03/13] qemu-threads: add QemuEvent
From: |
Blue Swirl |
Subject: |
Re: [Qemu-devel] [RFC PATCH 03/13] qemu-threads: add QemuEvent |
Date: |
Wed, 17 Aug 2011 17:09:55 +0000 |
On Mon, Aug 15, 2011 at 9:08 PM, Paolo Bonzini <address@hidden> wrote:
> This emulates Win32 manual-reset events using futexes or conditional
> variables. Typical ways to use them are with multi-producer,
> single-consumer data structures, to test for a complex condition whose
> elements come from different threads:
>
> for (;;) {
> qemu_event_reset(ev);
> ... test complex condition ...
> if (condition is true) {
> break;
> }
> qemu_event_wait(ev);
> }
>
> Alternatively:
>
> ... compute condition ...
> if (condition) {
> do {
> qemu_event_wait(ev);
> qemu_event_reset(ev);
> ... compute condition ...
> } while(condition);
> qemu_event_set(ev);
> }
>
> QemuEvent provides a very fast userspace path in the common case when
> no other thread is waiting, or the event is not changing state. It
> is used to report RCU quiescent states to the thread calling
> synchronize_rcu (the latter being the single consumer), and to report
> call_rcu invocations to the thread that receives them.
>
> Signed-off-by: Paolo Bonzini <address@hidden>
> ---
> qemu-thread-posix.c | 124
> +++++++++++++++++++++++++++++++++++++++++++++++++++
> qemu-thread-posix.h | 8 +++
> qemu-thread-win32.c | 26 +++++++++++
> qemu-thread-win32.h | 4 ++
> qemu-thread.h | 8 +++
> 5 files changed, 170 insertions(+), 0 deletions(-)
>
> diff --git a/qemu-thread-posix.c b/qemu-thread-posix.c
> index 2bd02ef..50e7421 100644
> --- a/qemu-thread-posix.c
> +++ b/qemu-thread-posix.c
> @@ -17,7 +17,10 @@
> #include <signal.h>
> #include <stdint.h>
> #include <string.h>
> +#include <limits.h>
> +#include <unistd.h>
> #include "qemu-thread.h"
> +#include "qemu-barrier.h"
>
> static void error_exit(int err, const char *msg)
> {
> @@ -115,6 +118,127 @@ void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
> error_exit(err, __func__);
> }
>
> +#ifdef __linux__
> +#include <sys/syscall.h>
futex manual page says
#include <linux/futex.h>
#include <sys/time.h>
Maybe the compatibility stuff below belongs to linux-headers.
> +#ifndef FUTEX_WAIT
> +#define FUTEX_WAIT 0
> +#endif
> +#ifndef FUTEX_WAKE
> +#define FUTEX_WAKE 1
> +#endif
> +
> +#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)
> +{
> + futex(ev, FUTEX_WAIT, (int) val, NULL, NULL, 0);
> +}
> +#else
> +static inline void futex_wake(QemuEvent *ev, int n)
> +{
> + if (n == 1)
Missing braces, please use checkpatch.pl.
> + pthread_cond_signal(&ev->cond);
> + else
> + pthread_cond_broadcast(&ev->cond);
> +}
> +
> +static inline void futex_wait(QemuEvent *ev, unsigned val)
> +{
> + pthread_mutex_lock(&ev->lock);
> + if (ev->value == val)
> + pthread_cond_wait(&ev->cond, &ev->lock);
> + pthread_mutex_unlock(&ev->lock);
> +}
> +#endif
> +
> +/* Bit 0 is 1 if there are no waiters. Bit 1 is 1 if the event is set.
> + * The combination "event_set && event_has_waiters" is impossible. */
> +#define EV_FREE_BIT 1
> +#define EV_SET_BIT 2
> +
> +#define EV_BUSY 0
> +#define EV_FREE 1
> +#define EV_SET 3
> +
> +void qemu_event_init(QemuEvent *ev, bool init)
> +{
> +#ifndef __linux__
> + pthread_mutex_init(&ev->lock, NULL);
> + pthread_cond_init(&ev->cond, NULL);
> +#endif
> +
> + ev->value = (init ? EV_SET : EV_FREE);
> +}
> +
> +void qemu_event_destroy(QemuEvent *ev)
> +{
> +#ifndef __linux__
> + pthread_mutex_destroy(&ev->lock);
> + pthread_cond_destroy(&ev->cond);
> +#endif
> +}
> +
> +void qemu_event_set(QemuEvent *ev)
> +{
> + unsigned value;
> +
> + smp_mb();
> + value = ev->value;
> + if (value == EV_SET) {
> + /* Exit on a pre-existing/concurrent set. */
> + smp_mb();
> + } else {
> + if (__sync_fetch_and_or(&ev->value, EV_SET) == EV_BUSY) {
> + /* There were waiters, wake them up. */
> + futex_wake(ev, INT_MAX);
> + }
> + }
> +}
> +
> +void qemu_event_reset(QemuEvent *ev)
> +{
> + unsigned value;
> +
> + smp_mb();
> + value = ev->value;
> + if (value != EV_SET) {
> + /* Exit on a pre-existing reset. */
> + smp_mb();
> + } else {
> + /* If there was a concurrent reset (or even reset+wait),
> + * do nothing. Otherwise change EV_SET->EV_FREE. */
> + __sync_fetch_and_and(&ev->value, ~EV_SET_BIT);
> + }
> +}
> +
> +void qemu_event_wait(QemuEvent *ev)
> +{
> + unsigned value, old;
> +
> + smp_mb();
> + value = ev->value;
> + if (value == EV_SET) {
> + smp_mb();
> + } else {
> + 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 concurent busy->free transition. After the CAS, the
> + * event will be either set or busy. */
> + old = __sync_val_compare_and_swap(&ev->value, EV_FREE, EV_BUSY);
> + if (old == EV_SET) {
> + return;
> + }
> + }
> + futex_wait(ev, EV_BUSY);
> + }
> +}
> +
> void qemu_thread_create(QemuThread *thread,
> void *(*start_routine)(void*),
> void *arg)
> diff --git a/qemu-thread-posix.h b/qemu-thread-posix.h
> index ee4618e..2f5b63d 100644
> --- a/qemu-thread-posix.h
> +++ b/qemu-thread-posix.h
> @@ -10,6 +10,14 @@ struct QemuCond {
> pthread_cond_t cond;
> };
>
> +struct QemuEvent {
> +#ifndef __linux__
> + pthread_mutex_t lock;
> + pthread_cond_t cond;
> +#endif
> + unsigned value;
> +};
> +
> struct QemuThread {
> pthread_t thread;
> };
> diff --git a/qemu-thread-win32.c b/qemu-thread-win32.c
> index 2d2d5ab..9bdbb48 100644
> --- a/qemu-thread-win32.c
> +++ b/qemu-thread-win32.c
> @@ -192,6 +192,32 @@ void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
> qemu_mutex_lock(mutex);
> }
>
> +void qemu_event_init(QemuEvent *ev, bool init)
> +{
> + /* Manual reset. */
> + ev->event = CreateEvent(NULL, TRUE, init, NULL);
> +}
> +
> +void qemu_event_destroy(QemuEvent *mutex)
> +{
> + CloseHandle(ev->event);
> +}
> +
> +void qemu_event_set(QemuEvent *ev)
> +{
> + SetEvent(ev->event);
> +}
> +
> +void qemu_event_reset(QemuEvent *ev)
> +{
> + ResetEvent(ev->event);
> +}
> +
> +void qemu_event_wait(QemuEvent *ev)
> +{
> + WaitForSingleObject(ev->event, INFINITE);
> +}
> +
> struct QemuThreadData {
> QemuThread *thread;
> void *(*start_routine)(void *);
> diff --git a/qemu-thread-win32.h b/qemu-thread-win32.h
> index 878f86a..ddd6d0f 100644
> --- a/qemu-thread-win32.h
> +++ b/qemu-thread-win32.h
> @@ -13,6 +13,10 @@ struct QemuCond {
> HANDLE continue_event;
> };
>
> +struct QemuEvent {
> + HANDLE event;
> +};
> +
> struct QemuThread {
> HANDLE thread;
> void *ret;
> diff --git a/qemu-thread.h b/qemu-thread.h
> index 0a73d50..8353e3d 100644
> --- a/qemu-thread.h
> +++ b/qemu-thread.h
> @@ -2,9 +2,11 @@
> #define __QEMU_THREAD_H 1
>
> #include <inttypes.h>
> +#include <stdbool.h>
>
> typedef struct QemuMutex QemuMutex;
> typedef struct QemuCond QemuCond;
> +typedef struct QemuEvent QemuEvent;
> typedef struct QemuThread QemuThread;
>
> #ifdef _WIN32
> @@ -31,6 +33,12 @@ void qemu_cond_signal(QemuCond *cond);
> void qemu_cond_broadcast(QemuCond *cond);
> void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex);
>
> +void qemu_event_init(QemuEvent *ev, bool init);
> +void qemu_event_set(QemuEvent *ev);
> +void qemu_event_reset(QemuEvent *ev);
> +void qemu_event_wait(QemuEvent *ev);
> +void qemu_event_destroy(QemuEvent *ev);
> +
> void qemu_thread_create(QemuThread *thread,
> void *(*start_routine)(void*),
> void *arg);
> --
> 1.7.6
>
>
>
>
- [Qemu-devel] [RFC PATCH 00/13] RCU implementation for QEMU, Paolo Bonzini, 2011/08/15
- [Qemu-devel] [RFC PATCH 01/13] add smp_mb(), Paolo Bonzini, 2011/08/15
- [Qemu-devel] [RFC PATCH 02/13] rename qemu_event_{init,read}, Paolo Bonzini, 2011/08/15
- [Qemu-devel] [RFC PATCH 03/13] qemu-threads: add QemuEvent, Paolo Bonzini, 2011/08/15
- Re: [Qemu-devel] [RFC PATCH 03/13] qemu-threads: add QemuEvent,
Blue Swirl <=
- [Qemu-devel] [RFC PATCH 04/13] qemu-threads: add QemuOnce, Paolo Bonzini, 2011/08/15
- [Qemu-devel] [RFC PATCH 06/13] rcu: add rcutorture, Paolo Bonzini, 2011/08/15
- [Qemu-devel] [RFC PATCH 05/13] add rcu library, Paolo Bonzini, 2011/08/15
- [Qemu-devel] [RFC PATCH 08/13] add call_rcu support, Paolo Bonzini, 2011/08/15
- [Qemu-devel] [RFC PATCH 10/13] rcu: report quiescent states, Paolo Bonzini, 2011/08/15
- [Qemu-devel] [RFC PATCH 11/13] rcuify iohandlers, Paolo Bonzini, 2011/08/15
- [Qemu-devel] [RFC PATCH 09/13] rcu: avoid repeated system calls, Paolo Bonzini, 2011/08/15
- [Qemu-devel] [RFC PATCH 12/13] split MRU ram list, Paolo Bonzini, 2011/08/15
- [Qemu-devel] [RFC PATCH 07/13] osdep: add qemu_msleep, Paolo Bonzini, 2011/08/15