[Top][All Lists]
[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?
- [Qemu-devel] [PATCH v2 uq/master 00/22] Win32 iothread support, Paolo Bonzini, 2011/02/26
- [Qemu-devel] [PATCH v2 upstream 01/22] unlock iothread during WaitForMultipleObjects, Paolo Bonzini, 2011/02/26
- [Qemu-devel] [PATCH v2 upstream 02/22] implement win32 dynticks timer, Paolo Bonzini, 2011/02/26
- [Qemu-devel] [PATCH v2 upstream 03/22] use win32 timer queues, Paolo Bonzini, 2011/02/26
- [Qemu-devel] [PATCH v2 upstream 04/22] Refactor thread retrieval and check, Paolo Bonzini, 2011/02/26
- [Qemu-devel] [PATCH v2 upstream 05/22] add win32 qemu-thread implementation, Paolo Bonzini, 2011/02/26
- Re: [Qemu-devel] [PATCH v2 upstream 05/22] add win32 qemu-thread implementation,
Blue Swirl <=
- [Qemu-devel] [PATCH v2 upstream 06/22] include qemu-thread.h early, Paolo Bonzini, 2011/02/26
- [Qemu-devel] [PATCH v2 upstream 07/22] add assertions on the owner of a QemuMutex, Paolo Bonzini, 2011/02/26
- [Qemu-devel] [PATCH v2 upstream 08/22] remove CONFIG_THREAD, Paolo Bonzini, 2011/02/26
- [Qemu-devel] [PATCH v2 upstream 09/22] target-sh4: move intr_at_halt out of cpu_halted(), Paolo Bonzini, 2011/02/26
- [Qemu-devel] [PATCH v2 upstream 10/22] inline cpu_halted into sole caller, Paolo Bonzini, 2011/02/26
- [Qemu-devel] [PATCH v2 upstream 11/22] always qemu_cpu_kick after unhalting a cpu, Paolo Bonzini, 2011/02/26
- [Qemu-devel] [PATCH v2 upstream 12/22] exit round-robin vcpu loop if cpu->stopped is true, Paolo Bonzini, 2011/02/26