| /* |
| * 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_destroy(QemuMutex *mutex) |
| { |
| assert(mutex->owner == 0); |
| DeleteCriticalSection(&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_destroy(QemuCond *cond) |
| { |
| BOOL result; |
| result = CloseHandle(cond->continue_event); |
| if (!result) { |
| error_exit(GetLastError(), __func__); |
| } |
| cond->continue_event = 0; |
| result = CloseHandle(cond->sema); |
| if (!result) { |
| error_exit(GetLastError(), __func__); |
| } |
| cond->sema = 0; |
| } |
| |
| 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 QemuThreadData { |
| QemuThread *thread; |
| void *(*start_routine)(void *); |
| void *arg; |
| }; |
| |
| static int qemu_thread_tls_index = TLS_OUT_OF_INDEXES; |
| |
| static unsigned __stdcall win32_start_routine(void *arg) |
| { |
| struct QemuThreadData data = *(struct QemuThreadData *) arg; |
| QemuThread *thread = data.thread; |
| |
| free(arg); |
| TlsSetValue(qemu_thread_tls_index, thread); |
| |
| /* |
| * Use DuplicateHandle instead of assigning thread->thread in the |
| * creating thread to avoid races. It's simpler this way than with |
| * synchronization. |
| */ |
| DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), |
| GetCurrentProcess(), &thread->thread, |
| 0, FALSE, DUPLICATE_SAME_ACCESS); |
| |
| qemu_thread_exit(data.start_routine(data.arg)); |
| abort(); |
| } |
| |
| void qemu_thread_exit(void *arg) |
| { |
| QemuThread *thread = TlsGetValue(qemu_thread_tls_index); |
| thread->ret = arg; |
| CloseHandle(thread->thread); |
| thread->thread = NULL; |
| ExitThread(0); |
| } |
| |
| static inline void qemu_thread_init(void) |
| { |
| if (qemu_thread_tls_index == TLS_OUT_OF_INDEXES) { |
| qemu_thread_tls_index = TlsAlloc(); |
| if (qemu_thread_tls_index == TLS_OUT_OF_INDEXES) { |
| error_exit(ERROR_NO_SYSTEM_RESOURCES, __func__); |
| } |
| } |
| } |
| |
| |
| void qemu_thread_create(QemuThread *thread, |
| void *(*start_routine)(void *), |
| void *arg) |
| { |
| HANDLE hThread; |
| |
| struct QemuThreadData *data; |
| qemu_thread_init(); |
| data = qemu_malloc(sizeof *data); |
| data->thread = thread; |
| data->start_routine = start_routine; |
| data->arg = arg; |
| |
| hThread = (HANDLE) _beginthreadex(NULL, 0, win32_start_routine, |
| data, 0, NULL); |
| if (!hThread) { |
| error_exit(GetLastError(), __func__); |
| } |
| CloseHandle(hThread); |
| } |
| |
| void qemu_thread_get_self(QemuThread *thread) |
| { |
| if (!thread->thread) { |
| /* In the main thread of the process. Initialize the QemuThread |
| pointer in TLS, and use the dummy GetCurrentThread handle as |
| the identifier for qemu_thread_is_self. */ |
| qemu_thread_init(); |
| TlsSetValue(qemu_thread_tls_index, thread); |
| thread->thread = GetCurrentThread(); |
| } |
| } |
| |
| int qemu_thread_is_self(QemuThread *thread) |
| { |
| QemuThread *this_thread = TlsGetValue(qemu_thread_tls_index); |
| return this_thread->thread == thread->thread; |
| } |