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