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