From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from [140.186.70.92] (port=51801 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PtOAV-0001x1-V9 for qemu-devel@nongnu.org; Sat, 26 Feb 2011 12:43:05 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PtOAQ-0007ui-HA for qemu-devel@nongnu.org; Sat, 26 Feb 2011 12:42:59 -0500 Received: from mail-wy0-f173.google.com ([74.125.82.173]:37289) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PtOAQ-0007ud-7u for qemu-devel@nongnu.org; Sat, 26 Feb 2011 12:42:54 -0500 Received: by wyb29 with SMTP id 29so2681001wyb.4 for ; Sat, 26 Feb 2011 09:42:53 -0800 (PST) Sender: Paolo Bonzini Message-ID: <4D693B9A.2060705@redhat.com> Date: Sat, 26 Feb 2011 18:42:50 +0100 From: Paolo Bonzini MIME-Version: 1.0 References: <1298734819-1960-1-git-send-email-pbonzini@redhat.com> <1298734819-1960-6-git-send-email-pbonzini@redhat.com> In-Reply-To: Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit Subject: [Qemu-devel] Re: [PATCH v2 upstream 05/22] add win32 qemu-thread implementation List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Blue Swirl Cc: jan.kiszka@siemens.com, qemu-devel@nongnu.org, aurelien@aurel32.net On 02/26/2011 05:47 PM, Blue Swirl wrote: > On Sat, Feb 26, 2011 at 5:40 PM, Paolo Bonzini 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 >> --- >> 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 >> + * >> + * 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 >> +#include >> +#include >> + >> +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