cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

qemu-thread-win32.c (11830B)


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