qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

qemu-thread-win32.c (13504B)


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