qemu/util/qemu-thread-win32.c
<<
>>
Prefs
   1/*
   2 * Win32 implementation for mutex/cond/thread functions
   3 *
   4 * Copyright Red Hat, Inc. 2010
   5 *
   6 * Author:
   7 *  Paolo Bonzini <pbonzini@redhat.com>
   8 *
   9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
  10 * See the COPYING file in the top-level directory.
  11 *
  12 */
  13
  14#ifndef _WIN32_WINNT
  15#define _WIN32_WINNT 0x0600
  16#endif
  17
  18#include "qemu/osdep.h"
  19#include "qemu-common.h"
  20#include "qemu/thread.h"
  21#include "qemu/notify.h"
  22#include "qemu-thread-common.h"
  23#include <process.h>
  24
  25static bool name_threads;
  26
  27void qemu_thread_naming(bool enable)
  28{
  29    /* But note we don't actually name them on Windows yet */
  30    name_threads = enable;
  31
  32    fprintf(stderr, "qemu: thread naming not supported on this host\n");
  33}
  34
  35static void error_exit(int err, const char *msg)
  36{
  37    char *pstr;
  38
  39    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  40                  NULL, err, 0, (LPTSTR)&pstr, 2, NULL);
  41    fprintf(stderr, "qemu: %s: %s\n", msg, pstr);
  42    LocalFree(pstr);
  43    abort();
  44}
  45
  46void qemu_mutex_init(QemuMutex *mutex)
  47{
  48    InitializeSRWLock(&mutex->lock);
  49    qemu_mutex_post_init(mutex);
  50}
  51
  52void qemu_mutex_destroy(QemuMutex *mutex)
  53{
  54    assert(mutex->initialized);
  55    mutex->initialized = false;
  56    InitializeSRWLock(&mutex->lock);
  57}
  58
  59void qemu_mutex_lock_impl(QemuMutex *mutex, const char *file, const int line)
  60{
  61    assert(mutex->initialized);
  62    qemu_mutex_pre_lock(mutex, file, line);
  63    AcquireSRWLockExclusive(&mutex->lock);
  64    qemu_mutex_post_lock(mutex, file, line);
  65}
  66
  67int qemu_mutex_trylock_impl(QemuMutex *mutex, const char *file, const int line)
  68{
  69    int owned;
  70
  71    assert(mutex->initialized);
  72    owned = TryAcquireSRWLockExclusive(&mutex->lock);
  73    if (owned) {
  74        qemu_mutex_post_lock(mutex, file, line);
  75        return 0;
  76    }
  77    return -EBUSY;
  78}
  79
  80void qemu_mutex_unlock_impl(QemuMutex *mutex, const char *file, const int line)
  81{
  82    assert(mutex->initialized);
  83    qemu_mutex_pre_unlock(mutex, file, line);
  84    ReleaseSRWLockExclusive(&mutex->lock);
  85}
  86
  87void qemu_rec_mutex_init(QemuRecMutex *mutex)
  88{
  89    InitializeCriticalSection(&mutex->lock);
  90    mutex->initialized = true;
  91}
  92
  93void qemu_rec_mutex_destroy(QemuRecMutex *mutex)
  94{
  95    assert(mutex->initialized);
  96    mutex->initialized = false;
  97    DeleteCriticalSection(&mutex->lock);
  98}
  99
 100void qemu_rec_mutex_lock_impl(QemuRecMutex *mutex, const char *file, int line)
 101{
 102    assert(mutex->initialized);
 103    EnterCriticalSection(&mutex->lock);
 104}
 105
 106int qemu_rec_mutex_trylock_impl(QemuRecMutex *mutex, const char *file, int line)
 107{
 108    assert(mutex->initialized);
 109    return !TryEnterCriticalSection(&mutex->lock);
 110}
 111
 112void qemu_rec_mutex_unlock(QemuRecMutex *mutex)
 113{
 114    assert(mutex->initialized);
 115    LeaveCriticalSection(&mutex->lock);
 116}
 117
 118void qemu_cond_init(QemuCond *cond)
 119{
 120    memset(cond, 0, sizeof(*cond));
 121    InitializeConditionVariable(&cond->var);
 122    cond->initialized = true;
 123}
 124
 125void qemu_cond_destroy(QemuCond *cond)
 126{
 127    assert(cond->initialized);
 128    cond->initialized = false;
 129    InitializeConditionVariable(&cond->var);
 130}
 131
 132void qemu_cond_signal(QemuCond *cond)
 133{
 134    assert(cond->initialized);
 135    WakeConditionVariable(&cond->var);
 136}
 137
 138void qemu_cond_broadcast(QemuCond *cond)
 139{
 140    assert(cond->initialized);
 141    WakeAllConditionVariable(&cond->var);
 142}
 143
 144void qemu_cond_wait_impl(QemuCond *cond, QemuMutex *mutex, const char *file, const int line)
 145{
 146    assert(cond->initialized);
 147    qemu_mutex_pre_unlock(mutex, file, line);
 148    SleepConditionVariableSRW(&cond->var, &mutex->lock, INFINITE, 0);
 149    qemu_mutex_post_lock(mutex, file, line);
 150}
 151
 152void qemu_sem_init(QemuSemaphore *sem, int init)
 153{
 154    /* Manual reset.  */
 155    sem->sema = CreateSemaphore(NULL, init, LONG_MAX, NULL);
 156    sem->initialized = true;
 157}
 158
 159void qemu_sem_destroy(QemuSemaphore *sem)
 160{
 161    assert(sem->initialized);
 162    sem->initialized = false;
 163    CloseHandle(sem->sema);
 164}
 165
 166void qemu_sem_post(QemuSemaphore *sem)
 167{
 168    assert(sem->initialized);
 169    ReleaseSemaphore(sem->sema, 1, NULL);
 170}
 171
 172int qemu_sem_timedwait(QemuSemaphore *sem, int ms)
 173{
 174    int rc;
 175
 176    assert(sem->initialized);
 177    rc = WaitForSingleObject(sem->sema, ms);
 178    if (rc == WAIT_OBJECT_0) {
 179        return 0;
 180    }
 181    if (rc != WAIT_TIMEOUT) {
 182        error_exit(GetLastError(), __func__);
 183    }
 184    return -1;
 185}
 186
 187void qemu_sem_wait(QemuSemaphore *sem)
 188{
 189    assert(sem->initialized);
 190    if (WaitForSingleObject(sem->sema, INFINITE) != WAIT_OBJECT_0) {
 191        error_exit(GetLastError(), __func__);
 192    }
 193}
 194
 195/* Wrap a Win32 manual-reset event with a fast userspace path.  The idea
 196 * is to reset the Win32 event lazily, as part of a test-reset-test-wait
 197 * sequence.  Such a sequence is, indeed, how QemuEvents are used by
 198 * RCU and other subsystems!
 199 *
 200 * Valid transitions:
 201 * - free->set, when setting the event
 202 * - busy->set, when setting the event, followed by SetEvent
 203 * - set->free, when resetting the event
 204 * - free->busy, when waiting
 205 *
 206 * set->busy does not happen (it can be observed from the outside but
 207 * it really is set->free->busy).
 208 *
 209 * busy->free provably cannot happen; to enforce it, the set->free transition
 210 * is done with an OR, which becomes a no-op if the event has concurrently
 211 * transitioned to free or busy (and is faster than cmpxchg).
 212 */
 213
 214#define EV_SET         0
 215#define EV_FREE        1
 216#define EV_BUSY       -1
 217
 218void qemu_event_init(QemuEvent *ev, bool init)
 219{
 220    /* Manual reset.  */
 221    ev->event = CreateEvent(NULL, TRUE, TRUE, NULL);
 222    ev->value = (init ? EV_SET : EV_FREE);
 223    ev->initialized = true;
 224}
 225
 226void qemu_event_destroy(QemuEvent *ev)
 227{
 228    assert(ev->initialized);
 229    ev->initialized = false;
 230    CloseHandle(ev->event);
 231}
 232
 233void qemu_event_set(QemuEvent *ev)
 234{
 235    assert(ev->initialized);
 236    /* qemu_event_set has release semantics, but because it *loads*
 237     * ev->value we need a full memory barrier here.
 238     */
 239    smp_mb();
 240    if (atomic_read(&ev->value) != EV_SET) {
 241        if (atomic_xchg(&ev->value, EV_SET) == EV_BUSY) {
 242            /* There were waiters, wake them up.  */
 243            SetEvent(ev->event);
 244        }
 245    }
 246}
 247
 248void qemu_event_reset(QemuEvent *ev)
 249{
 250    unsigned value;
 251
 252    assert(ev->initialized);
 253    value = atomic_read(&ev->value);
 254    smp_mb_acquire();
 255    if (value == EV_SET) {
 256        /* If there was a concurrent reset (or even reset+wait),
 257         * do nothing.  Otherwise change EV_SET->EV_FREE.
 258         */
 259        atomic_or(&ev->value, EV_FREE);
 260    }
 261}
 262
 263void qemu_event_wait(QemuEvent *ev)
 264{
 265    unsigned value;
 266
 267    assert(ev->initialized);
 268    value = atomic_read(&ev->value);
 269    smp_mb_acquire();
 270    if (value != EV_SET) {
 271        if (value == EV_FREE) {
 272            /* qemu_event_set is not yet going to call SetEvent, but we are
 273             * going to do another check for EV_SET below when setting EV_BUSY.
 274             * At that point it is safe to call WaitForSingleObject.
 275             */
 276            ResetEvent(ev->event);
 277
 278            /* Tell qemu_event_set that there are waiters.  No need to retry
 279             * because there cannot be a concurent busy->free transition.
 280             * After the CAS, the event will be either set or busy.
 281             */
 282            if (atomic_cmpxchg(&ev->value, EV_FREE, EV_BUSY) == EV_SET) {
 283                value = EV_SET;
 284            } else {
 285                value = EV_BUSY;
 286            }
 287        }
 288        if (value == EV_BUSY) {
 289            WaitForSingleObject(ev->event, INFINITE);
 290        }
 291    }
 292}
 293
 294struct QemuThreadData {
 295    /* Passed to win32_start_routine.  */
 296    void             *(*start_routine)(void *);
 297    void             *arg;
 298    short             mode;
 299    NotifierList      exit;
 300
 301    /* Only used for joinable threads. */
 302    bool              exited;
 303    void             *ret;
 304    CRITICAL_SECTION  cs;
 305};
 306
 307static bool atexit_registered;
 308static NotifierList main_thread_exit;
 309
 310static __thread QemuThreadData *qemu_thread_data;
 311
 312static void run_main_thread_exit(void)
 313{
 314    notifier_list_notify(&main_thread_exit, NULL);
 315}
 316
 317void qemu_thread_atexit_add(Notifier *notifier)
 318{
 319    if (!qemu_thread_data) {
 320        if (!atexit_registered) {
 321            atexit_registered = true;
 322            atexit(run_main_thread_exit);
 323        }
 324        notifier_list_add(&main_thread_exit, notifier);
 325    } else {
 326        notifier_list_add(&qemu_thread_data->exit, notifier);
 327    }
 328}
 329
 330void qemu_thread_atexit_remove(Notifier *notifier)
 331{
 332    notifier_remove(notifier);
 333}
 334
 335static unsigned __stdcall win32_start_routine(void *arg)
 336{
 337    QemuThreadData *data = (QemuThreadData *) arg;
 338    void *(*start_routine)(void *) = data->start_routine;
 339    void *thread_arg = data->arg;
 340
 341    qemu_thread_data = data;
 342    qemu_thread_exit(start_routine(thread_arg));
 343    abort();
 344}
 345
 346void qemu_thread_exit(void *arg)
 347{
 348    QemuThreadData *data = qemu_thread_data;
 349
 350    notifier_list_notify(&data->exit, NULL);
 351    if (data->mode == QEMU_THREAD_JOINABLE) {
 352        data->ret = arg;
 353        EnterCriticalSection(&data->cs);
 354        data->exited = true;
 355        LeaveCriticalSection(&data->cs);
 356    } else {
 357        g_free(data);
 358    }
 359    _endthreadex(0);
 360}
 361
 362void *qemu_thread_join(QemuThread *thread)
 363{
 364    QemuThreadData *data;
 365    void *ret;
 366    HANDLE handle;
 367
 368    data = thread->data;
 369    if (data->mode == QEMU_THREAD_DETACHED) {
 370        return NULL;
 371    }
 372
 373    /*
 374     * Because multiple copies of the QemuThread can exist via
 375     * qemu_thread_get_self, we need to store a value that cannot
 376     * leak there.  The simplest, non racy way is to store the TID,
 377     * discard the handle that _beginthreadex gives back, and
 378     * get another copy of the handle here.
 379     */
 380    handle = qemu_thread_get_handle(thread);
 381    if (handle) {
 382        WaitForSingleObject(handle, INFINITE);
 383        CloseHandle(handle);
 384    }
 385    ret = data->ret;
 386    DeleteCriticalSection(&data->cs);
 387    g_free(data);
 388    return ret;
 389}
 390
 391void qemu_thread_create(QemuThread *thread, const char *name,
 392                       void *(*start_routine)(void *),
 393                       void *arg, int mode)
 394{
 395    HANDLE hThread;
 396    struct QemuThreadData *data;
 397
 398    data = g_malloc(sizeof *data);
 399    data->start_routine = start_routine;
 400    data->arg = arg;
 401    data->mode = mode;
 402    data->exited = false;
 403    notifier_list_init(&data->exit);
 404
 405    if (data->mode != QEMU_THREAD_DETACHED) {
 406        InitializeCriticalSection(&data->cs);
 407    }
 408
 409    hThread = (HANDLE) _beginthreadex(NULL, 0, win32_start_routine,
 410                                      data, 0, &thread->tid);
 411    if (!hThread) {
 412        error_exit(GetLastError(), __func__);
 413    }
 414    CloseHandle(hThread);
 415    thread->data = data;
 416}
 417
 418void qemu_thread_get_self(QemuThread *thread)
 419{
 420    thread->data = qemu_thread_data;
 421    thread->tid = GetCurrentThreadId();
 422}
 423
 424HANDLE qemu_thread_get_handle(QemuThread *thread)
 425{
 426    QemuThreadData *data;
 427    HANDLE handle;
 428
 429    data = thread->data;
 430    if (data->mode == QEMU_THREAD_DETACHED) {
 431        return NULL;
 432    }
 433
 434    EnterCriticalSection(&data->cs);
 435    if (!data->exited) {
 436        handle = OpenThread(SYNCHRONIZE | THREAD_SUSPEND_RESUME |
 437                            THREAD_SET_CONTEXT, FALSE, thread->tid);
 438    } else {
 439        handle = NULL;
 440    }
 441    LeaveCriticalSection(&data->cs);
 442    return handle;
 443}
 444
 445bool qemu_thread_is_self(QemuThread *thread)
 446{
 447    return GetCurrentThreadId() == thread->tid;
 448}
 449