qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Paolo Bonzini <pbonzini@redhat.com>
To: Blue Swirl <blauwirbel@gmail.com>
Cc: jan.kiszka@siemens.com, qemu-devel@nongnu.org, aurelien@aurel32.net
Subject: [Qemu-devel] Re: [PATCH v2 upstream 05/22] add win32 qemu-thread implementation
Date: Sat, 26 Feb 2011 18:42:50 +0100	[thread overview]
Message-ID: <4D693B9A.2060705@redhat.com> (raw)
In-Reply-To: <AANLkTik9vPW9qYE=Ru226b-JbxrPMtxGMyAsvTp27uFP@mail.gmail.com>

On 02/26/2011 05:47 PM, Blue Swirl wrote:
> On Sat, Feb 26, 2011 at 5:40 PM, Paolo Bonzini<pbonzini@redhat.com>  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<pbonzini@redhat.com>
>> ---
>>   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<pbonzini@redhat.com>
>> + *
>> + * 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?

Ok, will resubmit asap.  Can you add this convention to checkpatch?

Paolo

  reply	other threads:[~2011-02-26 17:43 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-02-26 15:39 [Qemu-devel] [PATCH v2 uq/master 00/22] Win32 iothread support Paolo Bonzini
2011-02-26 15:39 ` [Qemu-devel] [PATCH v2 upstream 01/22] unlock iothread during WaitForMultipleObjects Paolo Bonzini
2011-02-26 15:39 ` [Qemu-devel] [PATCH v2 upstream 02/22] implement win32 dynticks timer Paolo Bonzini
2011-02-26 15:40 ` [Qemu-devel] [PATCH v2 upstream 03/22] use win32 timer queues Paolo Bonzini
2011-02-26 15:40 ` [Qemu-devel] [PATCH v2 upstream 04/22] Refactor thread retrieval and check Paolo Bonzini
2011-02-26 15:40 ` [Qemu-devel] [PATCH v2 upstream 05/22] add win32 qemu-thread implementation Paolo Bonzini
2011-02-26 16:47   ` Blue Swirl
2011-02-26 17:42     ` Paolo Bonzini [this message]
2011-02-26 15:40 ` [Qemu-devel] [PATCH v2 upstream 06/22] include qemu-thread.h early Paolo Bonzini
2011-02-26 15:40 ` [Qemu-devel] [PATCH v2 upstream 07/22] add assertions on the owner of a QemuMutex Paolo Bonzini
2011-02-27  9:33   ` [Qemu-devel] " Jan Kiszka
2011-02-27 15:06     ` Paolo Bonzini
2011-02-26 15:40 ` [Qemu-devel] [PATCH v2 upstream 08/22] remove CONFIG_THREAD Paolo Bonzini
2011-02-26 15:40 ` [Qemu-devel] [PATCH v2 upstream 09/22] target-sh4: move intr_at_halt out of cpu_halted() Paolo Bonzini
2011-02-26 15:40 ` [Qemu-devel] [PATCH v2 upstream 10/22] inline cpu_halted into sole caller Paolo Bonzini
2011-02-26 15:40 ` [Qemu-devel] [PATCH v2 upstream 11/22] always qemu_cpu_kick after unhalting a cpu Paolo Bonzini
2011-02-26 15:40 ` [Qemu-devel] [PATCH v2 upstream 12/22] exit round-robin vcpu loop if cpu->stopped is true Paolo Bonzini
2011-02-26 15:40 ` [Qemu-devel] [PATCH v2 upstream 13/22] always signal pause_cond after stopping a VCPU Paolo Bonzini
2011-02-26 15:40 ` [Qemu-devel] [PATCH v2 upstream 14/22] do not use timedwait on qemu_halt_cond Paolo Bonzini
2011-02-26 15:40 ` [Qemu-devel] [PATCH v2 upstream 15/22] do not use timedwait on qemu_system_cond Paolo Bonzini
2011-02-26 15:40 ` [Qemu-devel] [PATCH v2 upstream 16/22] do not use timedwait on qemu_pause_cond Paolo Bonzini
2011-02-26 15:40 ` [Qemu-devel] [PATCH v2 upstream 17/22] do not use timedwait on qemu_cpu_cond Paolo Bonzini
2011-02-26 15:40 ` [Qemu-devel] [PATCH v2 upstream 18/22] iothread stops the vcpu thread via IPI Paolo Bonzini
2011-02-26 15:40 ` [Qemu-devel] [PATCH v2 upstream 19/22] move blocking of signals to qemu_signalfd_init Paolo Bonzini
2011-02-27  9:41   ` [Qemu-devel] " Jan Kiszka
2011-02-27 15:07     ` Paolo Bonzini
2011-02-26 15:40 ` [Qemu-devel] [PATCH v2 upstream 20/22] provide dummy signal init functions for win32 Paolo Bonzini
2011-02-26 15:40 ` [Qemu-devel] [PATCH v2 upstream 21/22] protect qemu_cpu_kick_self for Win32 Paolo Bonzini
2011-02-26 15:40 ` [Qemu-devel] [PATCH v2 upstream 22/22] add Win32 IPI service Paolo Bonzini
2011-02-26 16:49 ` [Qemu-devel] [PATCH v2 uq/master 00/22] Win32 iothread support Blue Swirl
2011-02-27  9:47 ` [Qemu-devel] " Jan Kiszka

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=4D693B9A.2060705@redhat.com \
    --to=pbonzini@redhat.com \
    --cc=aurelien@aurel32.net \
    --cc=blauwirbel@gmail.com \
    --cc=jan.kiszka@siemens.com \
    --cc=qemu-devel@nongnu.org \
    /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).