|  | /* | 
|  | * 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/osdep.h" | 
|  | #include "qemu/thread.h" | 
|  | #include "qemu/notify.h" | 
|  | #include "qemu-thread-common.h" | 
|  | #include <process.h> | 
|  |  | 
|  | static bool name_threads; | 
|  |  | 
|  | typedef HRESULT (WINAPI *pSetThreadDescription) (HANDLE hThread, | 
|  | PCWSTR lpThreadDescription); | 
|  | static pSetThreadDescription SetThreadDescriptionFunc; | 
|  | static HMODULE kernel32_module; | 
|  |  | 
|  | static bool load_set_thread_description(void) | 
|  | { | 
|  | static gsize _init_once = 0; | 
|  |  | 
|  | if (g_once_init_enter(&_init_once)) { | 
|  | kernel32_module = LoadLibrary("kernel32.dll"); | 
|  | if (kernel32_module) { | 
|  | SetThreadDescriptionFunc = | 
|  | (pSetThreadDescription)GetProcAddress(kernel32_module, | 
|  | "SetThreadDescription"); | 
|  | if (!SetThreadDescriptionFunc) { | 
|  | FreeLibrary(kernel32_module); | 
|  | } | 
|  | } | 
|  | g_once_init_leave(&_init_once, 1); | 
|  | } | 
|  |  | 
|  | return !!SetThreadDescriptionFunc; | 
|  | } | 
|  |  | 
|  | void qemu_thread_naming(bool enable) | 
|  | { | 
|  | name_threads = enable; | 
|  |  | 
|  | if (enable && !load_set_thread_description()) { | 
|  | fprintf(stderr, "qemu: thread naming not supported on this host\n"); | 
|  | name_threads = false; | 
|  | } | 
|  | } | 
|  |  | 
|  | 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); | 
|  | abort(); | 
|  | } | 
|  |  | 
|  | void qemu_mutex_init(QemuMutex *mutex) | 
|  | { | 
|  | InitializeSRWLock(&mutex->lock); | 
|  | qemu_mutex_post_init(mutex); | 
|  | } | 
|  |  | 
|  | void qemu_mutex_destroy(QemuMutex *mutex) | 
|  | { | 
|  | assert(mutex->initialized); | 
|  | mutex->initialized = false; | 
|  | InitializeSRWLock(&mutex->lock); | 
|  | } | 
|  |  | 
|  | void qemu_mutex_lock_impl(QemuMutex *mutex, const char *file, const int line) | 
|  | { | 
|  | assert(mutex->initialized); | 
|  | qemu_mutex_pre_lock(mutex, file, line); | 
|  | AcquireSRWLockExclusive(&mutex->lock); | 
|  | qemu_mutex_post_lock(mutex, file, line); | 
|  | } | 
|  |  | 
|  | int qemu_mutex_trylock_impl(QemuMutex *mutex, const char *file, const int line) | 
|  | { | 
|  | int owned; | 
|  |  | 
|  | assert(mutex->initialized); | 
|  | owned = TryAcquireSRWLockExclusive(&mutex->lock); | 
|  | if (owned) { | 
|  | qemu_mutex_post_lock(mutex, file, line); | 
|  | return 0; | 
|  | } | 
|  | return -EBUSY; | 
|  | } | 
|  |  | 
|  | void qemu_mutex_unlock_impl(QemuMutex *mutex, const char *file, const int line) | 
|  | { | 
|  | assert(mutex->initialized); | 
|  | qemu_mutex_pre_unlock(mutex, file, line); | 
|  | ReleaseSRWLockExclusive(&mutex->lock); | 
|  | } | 
|  |  | 
|  | void qemu_rec_mutex_init(QemuRecMutex *mutex) | 
|  | { | 
|  | InitializeCriticalSection(&mutex->lock); | 
|  | mutex->initialized = true; | 
|  | } | 
|  |  | 
|  | void qemu_rec_mutex_destroy(QemuRecMutex *mutex) | 
|  | { | 
|  | assert(mutex->initialized); | 
|  | mutex->initialized = false; | 
|  | DeleteCriticalSection(&mutex->lock); | 
|  | } | 
|  |  | 
|  | void qemu_rec_mutex_lock_impl(QemuRecMutex *mutex, const char *file, int line) | 
|  | { | 
|  | assert(mutex->initialized); | 
|  | EnterCriticalSection(&mutex->lock); | 
|  | } | 
|  |  | 
|  | int qemu_rec_mutex_trylock_impl(QemuRecMutex *mutex, const char *file, int line) | 
|  | { | 
|  | assert(mutex->initialized); | 
|  | return !TryEnterCriticalSection(&mutex->lock); | 
|  | } | 
|  |  | 
|  | void qemu_rec_mutex_unlock_impl(QemuRecMutex *mutex, const char *file, int line) | 
|  | { | 
|  | assert(mutex->initialized); | 
|  | LeaveCriticalSection(&mutex->lock); | 
|  | } | 
|  |  | 
|  | void qemu_cond_init(QemuCond *cond) | 
|  | { | 
|  | memset(cond, 0, sizeof(*cond)); | 
|  | InitializeConditionVariable(&cond->var); | 
|  | cond->initialized = true; | 
|  | } | 
|  |  | 
|  | void qemu_cond_destroy(QemuCond *cond) | 
|  | { | 
|  | assert(cond->initialized); | 
|  | cond->initialized = false; | 
|  | InitializeConditionVariable(&cond->var); | 
|  | } | 
|  |  | 
|  | void qemu_cond_signal(QemuCond *cond) | 
|  | { | 
|  | assert(cond->initialized); | 
|  | WakeConditionVariable(&cond->var); | 
|  | } | 
|  |  | 
|  | void qemu_cond_broadcast(QemuCond *cond) | 
|  | { | 
|  | assert(cond->initialized); | 
|  | WakeAllConditionVariable(&cond->var); | 
|  | } | 
|  |  | 
|  | void qemu_cond_wait_impl(QemuCond *cond, QemuMutex *mutex, const char *file, const int line) | 
|  | { | 
|  | assert(cond->initialized); | 
|  | qemu_mutex_pre_unlock(mutex, file, line); | 
|  | SleepConditionVariableSRW(&cond->var, &mutex->lock, INFINITE, 0); | 
|  | qemu_mutex_post_lock(mutex, file, line); | 
|  | } | 
|  |  | 
|  | bool qemu_cond_timedwait_impl(QemuCond *cond, QemuMutex *mutex, int ms, | 
|  | const char *file, const int line) | 
|  | { | 
|  | int rc = 0; | 
|  |  | 
|  | assert(cond->initialized); | 
|  | trace_qemu_mutex_unlock(mutex, file, line); | 
|  | if (!SleepConditionVariableSRW(&cond->var, &mutex->lock, ms, 0)) { | 
|  | rc = GetLastError(); | 
|  | } | 
|  | trace_qemu_mutex_locked(mutex, file, line); | 
|  | if (rc && rc != ERROR_TIMEOUT) { | 
|  | error_exit(rc, __func__); | 
|  | } | 
|  | return rc != ERROR_TIMEOUT; | 
|  | } | 
|  |  | 
|  | void qemu_sem_init(QemuSemaphore *sem, int init) | 
|  | { | 
|  | /* Manual reset.  */ | 
|  | sem->sema = CreateSemaphore(NULL, init, LONG_MAX, NULL); | 
|  | sem->initialized = true; | 
|  | } | 
|  |  | 
|  | void qemu_sem_destroy(QemuSemaphore *sem) | 
|  | { | 
|  | assert(sem->initialized); | 
|  | sem->initialized = false; | 
|  | CloseHandle(sem->sema); | 
|  | } | 
|  |  | 
|  | void qemu_sem_post(QemuSemaphore *sem) | 
|  | { | 
|  | assert(sem->initialized); | 
|  | ReleaseSemaphore(sem->sema, 1, NULL); | 
|  | } | 
|  |  | 
|  | int qemu_sem_timedwait(QemuSemaphore *sem, int ms) | 
|  | { | 
|  | int rc; | 
|  |  | 
|  | assert(sem->initialized); | 
|  | rc = WaitForSingleObject(sem->sema, ms); | 
|  | if (rc == WAIT_OBJECT_0) { | 
|  | return 0; | 
|  | } | 
|  | if (rc != WAIT_TIMEOUT) { | 
|  | error_exit(GetLastError(), __func__); | 
|  | } | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | void qemu_sem_wait(QemuSemaphore *sem) | 
|  | { | 
|  | assert(sem->initialized); | 
|  | if (WaitForSingleObject(sem->sema, INFINITE) != WAIT_OBJECT_0) { | 
|  | error_exit(GetLastError(), __func__); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Wrap a Win32 manual-reset event with a fast userspace path.  The idea | 
|  | * is to reset the Win32 event lazily, as part of a test-reset-test-wait | 
|  | * sequence.  Such a sequence is, indeed, how QemuEvents are used by | 
|  | * RCU and other subsystems! | 
|  | * | 
|  | * Valid transitions: | 
|  | * - free->set, when setting the event | 
|  | * - busy->set, when setting the event, followed by SetEvent | 
|  | * - set->free, when resetting the event | 
|  | * - free->busy, when waiting | 
|  | * | 
|  | * set->busy does not happen (it can be observed from the outside but | 
|  | * it really is set->free->busy). | 
|  | * | 
|  | * busy->free provably cannot happen; to enforce it, the set->free transition | 
|  | * is done with an OR, which becomes a no-op if the event has concurrently | 
|  | * transitioned to free or busy (and is faster than cmpxchg). | 
|  | */ | 
|  |  | 
|  | #define EV_SET         0 | 
|  | #define EV_FREE        1 | 
|  | #define EV_BUSY       -1 | 
|  |  | 
|  | void qemu_event_init(QemuEvent *ev, bool init) | 
|  | { | 
|  | /* Manual reset.  */ | 
|  | ev->event = CreateEvent(NULL, TRUE, TRUE, NULL); | 
|  | ev->value = (init ? EV_SET : EV_FREE); | 
|  | ev->initialized = true; | 
|  | } | 
|  |  | 
|  | void qemu_event_destroy(QemuEvent *ev) | 
|  | { | 
|  | assert(ev->initialized); | 
|  | ev->initialized = false; | 
|  | CloseHandle(ev->event); | 
|  | } | 
|  |  | 
|  | void qemu_event_set(QemuEvent *ev) | 
|  | { | 
|  | assert(ev->initialized); | 
|  |  | 
|  | /* | 
|  | * Pairs with both qemu_event_reset() and qemu_event_wait(). | 
|  | * | 
|  | * qemu_event_set has release semantics, but because it *loads* | 
|  | * ev->value we need a full memory barrier here. | 
|  | */ | 
|  | smp_mb(); | 
|  | if (qatomic_read(&ev->value) != EV_SET) { | 
|  | int old = qatomic_xchg(&ev->value, EV_SET); | 
|  |  | 
|  | /* Pairs with memory barrier after ResetEvent.  */ | 
|  | smp_mb__after_rmw(); | 
|  | if (old == EV_BUSY) { | 
|  | /* There were waiters, wake them up.  */ | 
|  | SetEvent(ev->event); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void qemu_event_reset(QemuEvent *ev) | 
|  | { | 
|  | assert(ev->initialized); | 
|  |  | 
|  | /* | 
|  | * If there was a concurrent reset (or even reset+wait), | 
|  | * do nothing.  Otherwise change EV_SET->EV_FREE. | 
|  | */ | 
|  | qatomic_or(&ev->value, EV_FREE); | 
|  |  | 
|  | /* | 
|  | * Order reset before checking the condition in the caller. | 
|  | * Pairs with the first memory barrier in qemu_event_set(). | 
|  | */ | 
|  | smp_mb__after_rmw(); | 
|  | } | 
|  |  | 
|  | void qemu_event_wait(QemuEvent *ev) | 
|  | { | 
|  | unsigned value; | 
|  |  | 
|  | assert(ev->initialized); | 
|  |  | 
|  | /* | 
|  | * qemu_event_wait must synchronize with qemu_event_set even if it does | 
|  | * not go down the slow path, so this load-acquire is needed that | 
|  | * synchronizes with the first memory barrier in qemu_event_set(). | 
|  | * | 
|  | * If we do go down the slow path, there is no requirement at all: we | 
|  | * might miss a qemu_event_set() here but ultimately the memory barrier in | 
|  | * qemu_futex_wait() will ensure the check is done correctly. | 
|  | */ | 
|  | value = qatomic_load_acquire(&ev->value); | 
|  | if (value != EV_SET) { | 
|  | if (value == EV_FREE) { | 
|  | /* | 
|  | * Here the underlying kernel event is reset, but qemu_event_set is | 
|  | * not yet going to call SetEvent.  However, there will be another | 
|  | * check for EV_SET below when setting EV_BUSY.  At that point it | 
|  | * is safe to call WaitForSingleObject. | 
|  | */ | 
|  | ResetEvent(ev->event); | 
|  |  | 
|  | /* | 
|  | * It is not clear whether ResetEvent provides this barrier; kernel | 
|  | * APIs (KeResetEvent/KeClearEvent) do not.  Better safe than sorry! | 
|  | */ | 
|  | smp_mb(); | 
|  |  | 
|  | /* | 
|  | * Leave the event reset and tell qemu_event_set that there are | 
|  | * waiters.  No need to retry, because there cannot be a concurrent | 
|  | * busy->free transition.  After the CAS, the event will be either | 
|  | * set or busy. | 
|  | */ | 
|  | if (qatomic_cmpxchg(&ev->value, EV_FREE, EV_BUSY) == EV_SET) { | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * ev->value is now EV_BUSY.  Since we didn't observe EV_SET, | 
|  | * qemu_event_set() must observe EV_BUSY and call SetEvent(). | 
|  | */ | 
|  | WaitForSingleObject(ev->event, INFINITE); | 
|  | } | 
|  | } | 
|  |  | 
|  | struct QemuThreadData { | 
|  | /* Passed to win32_start_routine.  */ | 
|  | void             *(*start_routine)(void *); | 
|  | void             *arg; | 
|  | short             mode; | 
|  | NotifierList      exit; | 
|  |  | 
|  | /* Only used for joinable threads. */ | 
|  | bool              exited; | 
|  | void             *ret; | 
|  | CRITICAL_SECTION  cs; | 
|  | }; | 
|  |  | 
|  | static bool atexit_registered; | 
|  | static NotifierList main_thread_exit; | 
|  |  | 
|  | static __thread QemuThreadData *qemu_thread_data; | 
|  |  | 
|  | static void run_main_thread_exit(void) | 
|  | { | 
|  | notifier_list_notify(&main_thread_exit, NULL); | 
|  | } | 
|  |  | 
|  | void qemu_thread_atexit_add(Notifier *notifier) | 
|  | { | 
|  | if (!qemu_thread_data) { | 
|  | if (!atexit_registered) { | 
|  | atexit_registered = true; | 
|  | atexit(run_main_thread_exit); | 
|  | } | 
|  | notifier_list_add(&main_thread_exit, notifier); | 
|  | } else { | 
|  | notifier_list_add(&qemu_thread_data->exit, notifier); | 
|  | } | 
|  | } | 
|  |  | 
|  | void qemu_thread_atexit_remove(Notifier *notifier) | 
|  | { | 
|  | notifier_remove(notifier); | 
|  | } | 
|  |  | 
|  | static unsigned __stdcall win32_start_routine(void *arg) | 
|  | { | 
|  | QemuThreadData *data = (QemuThreadData *) arg; | 
|  | void *(*start_routine)(void *) = data->start_routine; | 
|  | void *thread_arg = data->arg; | 
|  |  | 
|  | qemu_thread_data = data; | 
|  | qemu_thread_exit(start_routine(thread_arg)); | 
|  | abort(); | 
|  | } | 
|  |  | 
|  | void qemu_thread_exit(void *arg) | 
|  | { | 
|  | QemuThreadData *data = qemu_thread_data; | 
|  |  | 
|  | notifier_list_notify(&data->exit, NULL); | 
|  | if (data->mode == QEMU_THREAD_JOINABLE) { | 
|  | data->ret = arg; | 
|  | EnterCriticalSection(&data->cs); | 
|  | data->exited = true; | 
|  | LeaveCriticalSection(&data->cs); | 
|  | } else { | 
|  | g_free(data); | 
|  | } | 
|  | _endthreadex(0); | 
|  | } | 
|  |  | 
|  | void *qemu_thread_join(QemuThread *thread) | 
|  | { | 
|  | QemuThreadData *data; | 
|  | void *ret; | 
|  | HANDLE handle; | 
|  |  | 
|  | data = thread->data; | 
|  | if (data->mode == QEMU_THREAD_DETACHED) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Because multiple copies of the QemuThread can exist via | 
|  | * qemu_thread_get_self, we need to store a value that cannot | 
|  | * leak there.  The simplest, non racy way is to store the TID, | 
|  | * discard the handle that _beginthreadex gives back, and | 
|  | * get another copy of the handle here. | 
|  | */ | 
|  | handle = qemu_thread_get_handle(thread); | 
|  | if (handle) { | 
|  | WaitForSingleObject(handle, INFINITE); | 
|  | CloseHandle(handle); | 
|  | } | 
|  | ret = data->ret; | 
|  | DeleteCriticalSection(&data->cs); | 
|  | g_free(data); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static bool set_thread_description(HANDLE h, const char *name) | 
|  | { | 
|  | HRESULT hr; | 
|  | g_autofree wchar_t *namew = NULL; | 
|  |  | 
|  | if (!load_set_thread_description()) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | namew = g_utf8_to_utf16(name, -1, NULL, NULL, NULL); | 
|  | if (!namew) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | hr = SetThreadDescriptionFunc(h, namew); | 
|  |  | 
|  | return SUCCEEDED(hr); | 
|  | } | 
|  |  | 
|  | void qemu_thread_create(QemuThread *thread, const char *name, | 
|  | void *(*start_routine)(void *), | 
|  | void *arg, int mode) | 
|  | { | 
|  | HANDLE hThread; | 
|  | struct QemuThreadData *data; | 
|  |  | 
|  | data = g_malloc(sizeof *data); | 
|  | data->start_routine = start_routine; | 
|  | data->arg = arg; | 
|  | data->mode = mode; | 
|  | data->exited = false; | 
|  | notifier_list_init(&data->exit); | 
|  |  | 
|  | if (data->mode != QEMU_THREAD_DETACHED) { | 
|  | InitializeCriticalSection(&data->cs); | 
|  | } | 
|  |  | 
|  | hThread = (HANDLE) _beginthreadex(NULL, 0, win32_start_routine, | 
|  | data, 0, &thread->tid); | 
|  | if (!hThread) { | 
|  | error_exit(GetLastError(), __func__); | 
|  | } | 
|  | if (name_threads && name && !set_thread_description(hThread, name)) { | 
|  | fprintf(stderr, "qemu: failed to set thread description: %s\n", name); | 
|  | } | 
|  | CloseHandle(hThread); | 
|  |  | 
|  | thread->data = data; | 
|  | } | 
|  |  | 
|  | int qemu_thread_set_affinity(QemuThread *thread, unsigned long *host_cpus, | 
|  | unsigned long nbits) | 
|  | { | 
|  | return -ENOSYS; | 
|  | } | 
|  |  | 
|  | int qemu_thread_get_affinity(QemuThread *thread, unsigned long **host_cpus, | 
|  | unsigned long *nbits) | 
|  | { | 
|  | return -ENOSYS; | 
|  | } | 
|  |  | 
|  | void qemu_thread_get_self(QemuThread *thread) | 
|  | { | 
|  | thread->data = qemu_thread_data; | 
|  | thread->tid = GetCurrentThreadId(); | 
|  | } | 
|  |  | 
|  | HANDLE qemu_thread_get_handle(QemuThread *thread) | 
|  | { | 
|  | QemuThreadData *data; | 
|  | HANDLE handle; | 
|  |  | 
|  | data = thread->data; | 
|  | if (data->mode == QEMU_THREAD_DETACHED) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | EnterCriticalSection(&data->cs); | 
|  | if (!data->exited) { | 
|  | handle = OpenThread(SYNCHRONIZE | THREAD_SUSPEND_RESUME | | 
|  | THREAD_SET_CONTEXT, FALSE, thread->tid); | 
|  | } else { | 
|  | handle = NULL; | 
|  | } | 
|  | LeaveCriticalSection(&data->cs); | 
|  | return handle; | 
|  | } | 
|  |  | 
|  | bool qemu_thread_is_self(QemuThread *thread) | 
|  | { | 
|  | return GetCurrentThreadId() == thread->tid; | 
|  | } |