On Sat, Feb 26, 2011 at 5:40 PM, Paolo Bonzini <pbonz...@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 <pbonz...@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 <pbonz...@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?