qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v2 upstream 05/22] add win32 qemu-thread impleme


From: Blue Swirl
Subject: Re: [Qemu-devel] [PATCH v2 upstream 05/22] add win32 qemu-thread implementation
Date: Sat, 26 Feb 2011 18:47:32 +0200

On Sat, Feb 26, 2011 at 5:40 PM, Paolo Bonzini <address@hidden> wrote:
> For now, qemu_cond_timedwait and qemu_mutex_timedlock are left as
> POSIX-only functions.  They can be removed later, once the patches
> that remove their uses are in.
>
> Signed-off-by: Paolo Bonzini <address@hidden>
> ---
>  Makefile.objs                        |    4 +-
>  qemu-thread.c => qemu-thread-posix.c |    0
>  qemu-thread-posix.h                  |   18 +++
>  qemu-thread-win32.c                  |  260 
> ++++++++++++++++++++++++++++++++++
>  qemu-thread-win32.h                  |   21 +++
>  qemu-thread.h                        |   27 ++--
>  6 files changed, 313 insertions(+), 17 deletions(-)
>  rename qemu-thread.c => qemu-thread-posix.c (100%)
>  create mode 100644 qemu-thread-posix.h
>  create mode 100644 qemu-thread-win32.c
>  create mode 100644 qemu-thread-win32.h
>
> diff --git a/Makefile.objs b/Makefile.objs
> index 9e98a66..a52f42f 100644
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -142,8 +142,8 @@ endif
>  common-obj-y += $(addprefix ui/, $(ui-obj-y))
>
>  common-obj-y += iov.o acl.o
> -common-obj-$(CONFIG_THREAD) += qemu-thread.o
> -common-obj-$(CONFIG_POSIX) += compatfd.o
> +common-obj-$(CONFIG_POSIX) += qemu-thread-posix.o compatfd.o
> +common-obj-$(CONFIG_WIN32) += qemu-thread-win32.o
>  common-obj-y += notify.o event_notifier.o
>  common-obj-y += qemu-timer.o qemu-timer-common.o
>
> diff --git a/qemu-thread.c b/qemu-thread-posix.c
> similarity index 100%
> rename from qemu-thread.c
> rename to qemu-thread-posix.c
> diff --git a/qemu-thread-posix.h b/qemu-thread-posix.h
> new file mode 100644
> index 0000000..7af371c
> --- /dev/null
> +++ b/qemu-thread-posix.h
> @@ -0,0 +1,18 @@
> +#ifndef __QEMU_THREAD_POSIX_H
> +#define __QEMU_THREAD_POSIX_H 1
> +#include "pthread.h"
> +
> +struct QemuMutex {
> +    pthread_mutex_t lock;
> +};
> +
> +struct QemuCond {
> +    pthread_cond_t cond;
> +};
> +
> +struct QemuThread {
> +    pthread_t thread;
> +};
> +
> +void qemu_thread_signal(QemuThread *thread, int sig);
> +#endif
> diff --git a/qemu-thread-win32.c b/qemu-thread-win32.c
> new file mode 100644
> index 0000000..89422ce
> --- /dev/null
> +++ b/qemu-thread-win32.c
> @@ -0,0 +1,260 @@
> +/*
> + * Win32 implementation for mutex/cond/thread functions
> + *
> + * Copyright Red Hat, Inc. 2010
> + *
> + * Author:
> + *  Paolo Bonzini <address@hidden>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + *
> + */
> +#include "qemu-common.h"
> +#include "qemu-thread.h"
> +#include <process.h>
> +#include <assert.h>
> +#include <limits.h>
> +
> +static void error_exit(int err, const char *msg)
> +{
> +    char *pstr;
> +
> +    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | 
> FORMAT_MESSAGE_ALLOCATE_BUFFER,
> +                  NULL, err, 0, (LPTSTR)&pstr, 2, NULL);
> +    fprintf(stderr, "qemu: %s: %s\n", msg, pstr);
> +    LocalFree(pstr);
> +    exit(1);
> +}
> +
> +void qemu_mutex_init(QemuMutex *mutex)
> +{
> +    mutex->owner = 0;
> +    InitializeCriticalSection(&mutex->lock);
> +}
> +
> +void qemu_mutex_lock(QemuMutex *mutex)
> +{
> +    EnterCriticalSection(&mutex->lock);
> +
> +    /* Win32 CRITICAL_SECTIONs are recursive.  Assert that we're not
> +     * using them as such.
> +     */
> +    assert(mutex->owner == 0);
> +    mutex->owner = GetCurrentThreadId();
> +}
> +
> +int qemu_mutex_trylock(QemuMutex *mutex)
> +{
> +    int owned;
> +
> +    owned = TryEnterCriticalSection(&mutex->lock);
> +    if (owned) {
> +        assert(mutex->owner == 0);
> +        mutex->owner = GetCurrentThreadId();
> +    }
> +    return !owned;
> +}
> +
> +void qemu_mutex_unlock(QemuMutex *mutex)
> +{
> +    assert(mutex->owner == GetCurrentThreadId());
> +    mutex->owner = 0;
> +    LeaveCriticalSection(&mutex->lock);
> +}
> +
> +void qemu_cond_init(QemuCond *cond)
> +{
> +    memset(cond, 0, sizeof(*cond));
> +
> +    cond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL);
> +    if (!cond->sema) {
> +        error_exit(GetLastError(), __func__);
> +    }
> +    cond->continue_event = CreateEvent(NULL,    /* security */
> +                                       FALSE,   /* auto-reset */
> +                                       FALSE,   /* not signaled */
> +                                       NULL);   /* name */
> +    if (!cond->continue_event) {
> +        error_exit(GetLastError(), __func__);
> +    }
> +}
> +
> +void qemu_cond_signal(QemuCond *cond)
> +{
> +    DWORD result;
> +
> +    /*
> +     * Signal only when there are waiters.  cond->waiters is
> +     * incremented by pthread_cond_wait under the external lock,
> +     * so we are safe about that.
> +     */
> +    if (cond->waiters == 0) {
> +        return;
> +    }
> +
> +    /*
> +     * Waiting threads decrement it outside the external lock, but
> +     * only if another thread is executing pthread_cond_broadcast and
> +     * has the mutex.  So, it also cannot be decremented concurrently
> +     * with this particular access.
> +     */
> +    cond->target = cond->waiters - 1;
> +    result = SignalObjectAndWait(cond->sema, cond->continue_event,
> +                                 INFINITE, FALSE);
> +    if (result == WAIT_ABANDONED || result == WAIT_FAILED) {
> +        error_exit(GetLastError(), __func__);
> +    }
> +}
> +
> +void qemu_cond_broadcast(QemuCond *cond)
> +{
> +    BOOLEAN result;
> +    /*
> +     * As in pthread_cond_signal, access to cond->waiters and
> +     * cond->target is locked via the external mutex.
> +     */
> +    if (cond->waiters == 0) {
> +        return;
> +    }
> +
> +    cond->target = 0;
> +    result = ReleaseSemaphore(cond->sema, cond->waiters, NULL);
> +    if (!result) {
> +        error_exit(GetLastError(), __func__);
> +    }
> +
> +    /*
> +     * At this point all waiters continue. Each one takes its
> +     * slice of the semaphore. Now it's our turn to wait: Since
> +     * the external mutex is held, no thread can leave cond_wait,
> +     * yet. For this reason, we can be sure that no thread gets
> +     * a chance to eat *more* than one slice. OTOH, it means
> +     * that the last waiter must send us a wake-up.
> +     */
> +    WaitForSingleObject(cond->continue_event, INFINITE);
> +}
> +
> +void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
> +{
> +    /*
> +     * This access is protected under the mutex.
> +     */
> +    cond->waiters++;
> +
> +    /*
> +     * Unlock external mutex and wait for signal.
> +     * NOTE: we've held mutex locked long enough to increment
> +     * waiters count above, so there's no problem with
> +     * leaving mutex unlocked before we wait on semaphore.
> +     */
> +    qemu_mutex_unlock(mutex);
> +    WaitForSingleObject(cond->sema, INFINITE);
> +
> +    /* Now waiters must rendez-vous with the signaling thread and
> +     * let it continue.  For cond_broadcast this has heavy contention
> +     * and triggers thundering herd.  So goes life.
> +     *
> +     * Decrease waiters count.  The mutex is not taken, so we have
> +     * to do this atomically.
> +     *
> +     * All waiters contend for the mutex at the end of this function
> +     * until the signaling thread relinquishes it.  To ensure
> +     * each waiter consumes exactly one slice of the semaphore,
> +     * the signaling thread stops until it is told by the last
> +     * waiter that it can go on.
> +     */
> +    if (InterlockedDecrement(&cond->waiters) == cond->target) {
> +        SetEvent(cond->continue_event);
> +    }
> +
> +    qemu_mutex_lock(mutex);
> +}
> +
> +struct qemu_thread_data {

QemuThreadData?



reply via email to

[Prev in Thread] Current Thread [Next in Thread]