qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Jan Kiszka <jan.kiszka@siemens.com>
To: Liu Ping Fan <qemulist@gmail.com>
Cc: Alex Bligh <alex@alex.org.uk>,
	Paolo Bonzini <pbonzini@redhat.com>,
	Kevin Wolf <kwolf@redhat.com>,
	qemu-devel@nongnu.org, Stefan Hajnoczi <stefanha@redhat.com>
Subject: Re: [Qemu-devel] [PATCH v4 3/4] qemu-thread: add QemuEvent
Date: Mon, 23 Sep 2013 08:23:41 +0200	[thread overview]
Message-ID: <523FDE6D.2080802@siemens.com> (raw)
In-Reply-To: <1379837479-8419-5-git-send-email-pingfank@linux.vnet.ibm.com>

On 2013-09-22 10:11, Liu Ping Fan 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);
>     }
> 
> Or more efficiently (but with some duplication):
> 
>     ... evaluate condition ...
>     while (!condition) {
>         qemu_event_reset(ev);
>         ... evaluate condition ...
>         if (!condition) {
>             qemu_event_wait(ev);
>             ... evaluate condition ...
>         }
>     }
> 
> 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 <pbonzini@redhat.com>

Again, from and signed-off mismatch.

BTW, above is a good template for a commit log of patch 1.

Jan

> ---
>  include/qemu/thread-posix.h |   8 +++
>  include/qemu/thread-win32.h |   4 ++
>  include/qemu/thread.h       |   7 +++
>  util/qemu-thread-posix.c    | 116 ++++++++++++++++++++++++++++++++++++++++++++
>  util/qemu-thread-win32.c    |  26 ++++++++++
>  5 files changed, 161 insertions(+)
> 
> diff --git a/include/qemu/thread-posix.h b/include/qemu/thread-posix.h
> index 361566a..eb5c7a1 100644
> --- a/include/qemu/thread-posix.h
> +++ b/include/qemu/thread-posix.h
> @@ -21,6 +21,14 @@ struct QemuSemaphore {
>  #endif
>  };
>  
> +struct QemuEvent {
> +#ifndef __linux__
> +    pthread_mutex_t lock;
> +    pthread_cond_t cond;
> +#endif
> +    unsigned value;
> +};
> +
>  struct QemuThread {
>      pthread_t thread;
>  };
> diff --git a/include/qemu/thread-win32.h b/include/qemu/thread-win32.h
> index 13adb95..3d58081 100644
> --- a/include/qemu/thread-win32.h
> +++ b/include/qemu/thread-win32.h
> @@ -17,6 +17,10 @@ struct QemuSemaphore {
>      HANDLE sema;
>  };
>  
> +struct QemuEvent {
> +    HANDLE event;
> +};
> +
>  typedef struct QemuThreadData QemuThreadData;
>  struct QemuThread {
>      QemuThreadData *data;
> diff --git a/include/qemu/thread.h b/include/qemu/thread.h
> index c02404b..3e32c65 100644
> --- a/include/qemu/thread.h
> +++ b/include/qemu/thread.h
> @@ -7,6 +7,7 @@
>  typedef struct QemuMutex QemuMutex;
>  typedef struct QemuCond QemuCond;
>  typedef struct QemuSemaphore QemuSemaphore;
> +typedef struct QemuEvent QemuEvent;
>  typedef struct QemuThread QemuThread;
>  
>  #ifdef _WIN32
> @@ -45,6 +46,12 @@ void qemu_sem_wait(QemuSemaphore *sem);
>  int qemu_sem_timedwait(QemuSemaphore *sem, int ms);
>  void qemu_sem_destroy(QemuSemaphore *sem);
>  
> +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, int mode);
> diff --git a/util/qemu-thread-posix.c b/util/qemu-thread-posix.c
> index 4de133e..37dd298 100644
> --- a/util/qemu-thread-posix.c
> +++ b/util/qemu-thread-posix.c
> @@ -20,7 +20,12 @@
>  #include <limits.h>
>  #include <unistd.h>
>  #include <sys/time.h>
> +#ifdef __linux__
> +#include <sys/syscall.h>
> +#include <linux/futex.h>
> +#endif
>  #include "qemu/thread.h"
> +#include "qemu/atomic.h"
>  
>  static void error_exit(int err, const char *msg)
>  {
> @@ -272,6 +277,117 @@ void qemu_sem_wait(QemuSemaphore *sem)
>  #endif
>  }
>  
> +#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)
> +{
> +    futex(ev, FUTEX_WAIT, (int) val, NULL, NULL, 0);
> +}
> +#else
> +static inline void futex_wake(QemuEvent *ev, int n)
> +{
> +    if (n == 1) {
> +        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
> +
> +/* Valid transitions:
> + * - free->set, when setting the event
> + * - busy->set, when setting the event, followed by futex_wake
> + * - set->free, when resetting the event
> + * - free->busy, when waiting
> + *
> + * 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 __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)
> +{
> +    if (atomic_mb_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);
> +        }
> +    }
> +}
> +
> +void qemu_event_reset(QemuEvent *ev)
> +{
> +    if (atomic_mb_read(&ev->value) == EV_SET) {
> +        /*
> +         * If there was a concurrent reset (or even reset+wait),
> +         * do nothing.  Otherwise change EV_SET->EV_FREE.
> +         */
> +        atomic_or(&ev->value, EV_FREE);
> +    }
> +}
> +
> +void qemu_event_wait(QemuEvent *ev)
> +{
> +    unsigned value;
> +
> +    value = atomic_mb_read(&ev->value);
> +    if (value != EV_SET) {
> +        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.
> +             */
> +            if (atomic_cmpxchg(&ev->value, EV_FREE, EV_BUSY) == EV_SET) {
> +                return;
> +            }
> +        }
> +        futex_wait(ev, EV_BUSY);
> +    }
> +}
> +
> +
>  void qemu_thread_create(QemuThread *thread,
>                         void *(*start_routine)(void*),
>                         void *arg, int mode)
> diff --git a/util/qemu-thread-win32.c b/util/qemu-thread-win32.c
> index 517878d..27a5217 100644
> --- a/util/qemu-thread-win32.c
> +++ b/util/qemu-thread-win32.c
> @@ -227,6 +227,32 @@ void qemu_sem_wait(QemuSemaphore *sem)
>      }
>  }
>  
> +void qemu_event_init(QemuEvent *ev, bool init)
> +{
> +    /* Manual reset.  */
> +    ev->event = CreateEvent(NULL, TRUE, init, NULL);
> +}
> +
> +void qemu_event_destroy(QemuEvent *ev)
> +{
> +    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 {
>      /* Passed to win32_start_routine.  */
>      void             *(*start_routine)(void *);
> 

-- 
Siemens AG, Corporate Technology, CT RTC ITP SES-DE
Corporate Competence Center Embedded Linux

  reply	other threads:[~2013-09-23  6:24 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-09-22  8:11 [Qemu-devel] [PATCH v4 0/4] timers thread-safe stuff Liu Ping Fan
2013-09-22  8:11 ` [Qemu-devel] [PATCH v4 1/4] seqlock: introduce read-write seqlock Liu Ping Fan
2013-09-23  6:21   ` Jan Kiszka
2013-09-24  5:33     ` liu ping fan
2013-09-24  8:13       ` Paolo Bonzini
2013-09-22  8:11 ` Liu Ping Fan
2013-09-22  8:11 ` [Qemu-devel] [PATCH v4 2/4] timer: protect timers_state's clock with seqlock Liu Ping Fan
2013-09-23  6:21   ` Jan Kiszka
2013-09-24  6:15     ` liu ping fan
2013-09-22  8:11 ` [Qemu-devel] [PATCH v4 3/4] qemu-thread: add QemuEvent Liu Ping Fan
2013-09-23  6:23   ` Jan Kiszka [this message]
2013-09-22  8:11 ` [Qemu-devel] [PATCH v4 4/4] timer: make qemu_clock_enable sync between disable and timer's cb Liu Ping Fan
2013-09-23  6:26   ` Jan Kiszka
2013-09-24  5:40     ` liu ping fan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=523FDE6D.2080802@siemens.com \
    --to=jan.kiszka@siemens.com \
    --cc=alex@alex.org.uk \
    --cc=kwolf@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=qemulist@gmail.com \
    --cc=stefanha@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).