xref: /openbmc/qemu/util/qemu-thread-win32.c (revision 6c5df4b4)
1baacf047SPaolo Bonzini /*
2baacf047SPaolo Bonzini  * Win32 implementation for mutex/cond/thread functions
3baacf047SPaolo Bonzini  *
4baacf047SPaolo Bonzini  * Copyright Red Hat, Inc. 2010
5baacf047SPaolo Bonzini  *
6baacf047SPaolo Bonzini  * Author:
7baacf047SPaolo Bonzini  *  Paolo Bonzini <pbonzini@redhat.com>
8baacf047SPaolo Bonzini  *
9baacf047SPaolo Bonzini  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10baacf047SPaolo Bonzini  * See the COPYING file in the top-level directory.
11baacf047SPaolo Bonzini  *
12baacf047SPaolo Bonzini  */
1312f8def0SAndrey Shedel 
14aafd7584SPeter Maydell #include "qemu/osdep.h"
15baacf047SPaolo Bonzini #include "qemu/thread.h"
16ef57137fSPaolo Bonzini #include "qemu/notify.h"
17f1aff7aaSPeter Xu #include "qemu-thread-common.h"
18baacf047SPaolo Bonzini #include <process.h>
19baacf047SPaolo Bonzini 
208f480de0SDr. David Alan Gilbert static bool name_threads;
218f480de0SDr. David Alan Gilbert 
224db99c9dSMarc-André Lureau typedef HRESULT (WINAPI *pSetThreadDescription) (HANDLE hThread,
234db99c9dSMarc-André Lureau                                                  PCWSTR lpThreadDescription);
244db99c9dSMarc-André Lureau static pSetThreadDescription SetThreadDescriptionFunc;
254db99c9dSMarc-André Lureau static HMODULE kernel32_module;
264db99c9dSMarc-André Lureau 
load_set_thread_description(void)274db99c9dSMarc-André Lureau static bool load_set_thread_description(void)
284db99c9dSMarc-André Lureau {
294db99c9dSMarc-André Lureau     static gsize _init_once = 0;
304db99c9dSMarc-André Lureau 
314db99c9dSMarc-André Lureau     if (g_once_init_enter(&_init_once)) {
324db99c9dSMarc-André Lureau         kernel32_module = LoadLibrary("kernel32.dll");
334db99c9dSMarc-André Lureau         if (kernel32_module) {
344db99c9dSMarc-André Lureau             SetThreadDescriptionFunc =
354db99c9dSMarc-André Lureau                 (pSetThreadDescription)GetProcAddress(kernel32_module,
364db99c9dSMarc-André Lureau                                                       "SetThreadDescription");
374db99c9dSMarc-André Lureau             if (!SetThreadDescriptionFunc) {
384db99c9dSMarc-André Lureau                 FreeLibrary(kernel32_module);
394db99c9dSMarc-André Lureau             }
404db99c9dSMarc-André Lureau         }
414db99c9dSMarc-André Lureau         g_once_init_leave(&_init_once, 1);
424db99c9dSMarc-André Lureau     }
434db99c9dSMarc-André Lureau 
444db99c9dSMarc-André Lureau     return !!SetThreadDescriptionFunc;
454db99c9dSMarc-André Lureau }
464db99c9dSMarc-André Lureau 
qemu_thread_naming(bool enable)478f480de0SDr. David Alan Gilbert void qemu_thread_naming(bool enable)
488f480de0SDr. David Alan Gilbert {
498f480de0SDr. David Alan Gilbert     name_threads = enable;
505c312079SDr. David Alan Gilbert 
514db99c9dSMarc-André Lureau     if (enable && !load_set_thread_description()) {
525c312079SDr. David Alan Gilbert         fprintf(stderr, "qemu: thread naming not supported on this host\n");
534db99c9dSMarc-André Lureau         name_threads = false;
544db99c9dSMarc-André Lureau     }
558f480de0SDr. David Alan Gilbert }
568f480de0SDr. David Alan Gilbert 
error_exit(int err,const char * msg)57baacf047SPaolo Bonzini static void error_exit(int err, const char *msg)
58baacf047SPaolo Bonzini {
59baacf047SPaolo Bonzini     char *pstr;
60baacf047SPaolo Bonzini 
61baacf047SPaolo Bonzini     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
62baacf047SPaolo Bonzini                   NULL, err, 0, (LPTSTR)&pstr, 2, NULL);
63baacf047SPaolo Bonzini     fprintf(stderr, "qemu: %s: %s\n", msg, pstr);
64baacf047SPaolo Bonzini     LocalFree(pstr);
65baacf047SPaolo Bonzini     abort();
66baacf047SPaolo Bonzini }
67baacf047SPaolo Bonzini 
qemu_mutex_init(QemuMutex * mutex)68baacf047SPaolo Bonzini void qemu_mutex_init(QemuMutex *mutex)
69baacf047SPaolo Bonzini {
7012f8def0SAndrey Shedel     InitializeSRWLock(&mutex->lock);
71f1aff7aaSPeter Xu     qemu_mutex_post_init(mutex);
72baacf047SPaolo Bonzini }
73baacf047SPaolo Bonzini 
qemu_mutex_destroy(QemuMutex * mutex)74baacf047SPaolo Bonzini void qemu_mutex_destroy(QemuMutex *mutex)
75baacf047SPaolo Bonzini {
76c096358eSFam Zheng     assert(mutex->initialized);
77c096358eSFam Zheng     mutex->initialized = false;
7812f8def0SAndrey Shedel     InitializeSRWLock(&mutex->lock);
79baacf047SPaolo Bonzini }
80baacf047SPaolo Bonzini 
qemu_mutex_lock_impl(QemuMutex * mutex,const char * file,const int line)816c27a0deSAlex Bennée void qemu_mutex_lock_impl(QemuMutex *mutex, const char *file, const int line)
82baacf047SPaolo Bonzini {
83c096358eSFam Zheng     assert(mutex->initialized);
84f1aff7aaSPeter Xu     qemu_mutex_pre_lock(mutex, file, line);
8512f8def0SAndrey Shedel     AcquireSRWLockExclusive(&mutex->lock);
86f1aff7aaSPeter Xu     qemu_mutex_post_lock(mutex, file, line);
87baacf047SPaolo Bonzini }
88baacf047SPaolo Bonzini 
qemu_mutex_trylock_impl(QemuMutex * mutex,const char * file,const int line)896c27a0deSAlex Bennée int qemu_mutex_trylock_impl(QemuMutex *mutex, const char *file, const int line)
90baacf047SPaolo Bonzini {
91baacf047SPaolo Bonzini     int owned;
92baacf047SPaolo Bonzini 
93c096358eSFam Zheng     assert(mutex->initialized);
9412f8def0SAndrey Shedel     owned = TryAcquireSRWLockExclusive(&mutex->lock);
9531f5a726SJose Ricardo Ziviani     if (owned) {
96f1aff7aaSPeter Xu         qemu_mutex_post_lock(mutex, file, line);
9731f5a726SJose Ricardo Ziviani         return 0;
9831f5a726SJose Ricardo Ziviani     }
9931f5a726SJose Ricardo Ziviani     return -EBUSY;
100baacf047SPaolo Bonzini }
101baacf047SPaolo Bonzini 
qemu_mutex_unlock_impl(QemuMutex * mutex,const char * file,const int line)1026c27a0deSAlex Bennée void qemu_mutex_unlock_impl(QemuMutex *mutex, const char *file, const int line)
103baacf047SPaolo Bonzini {
104c096358eSFam Zheng     assert(mutex->initialized);
105f1aff7aaSPeter Xu     qemu_mutex_pre_unlock(mutex, file, line);
10612f8def0SAndrey Shedel     ReleaseSRWLockExclusive(&mutex->lock);
107baacf047SPaolo Bonzini }
108baacf047SPaolo Bonzini 
qemu_rec_mutex_init(QemuRecMutex * mutex)109feadec63SPaolo Bonzini void qemu_rec_mutex_init(QemuRecMutex *mutex)
110feadec63SPaolo Bonzini {
111feadec63SPaolo Bonzini     InitializeCriticalSection(&mutex->lock);
112c096358eSFam Zheng     mutex->initialized = true;
113feadec63SPaolo Bonzini }
114feadec63SPaolo Bonzini 
qemu_rec_mutex_destroy(QemuRecMutex * mutex)115feadec63SPaolo Bonzini void qemu_rec_mutex_destroy(QemuRecMutex *mutex)
116feadec63SPaolo Bonzini {
117c096358eSFam Zheng     assert(mutex->initialized);
118c096358eSFam Zheng     mutex->initialized = false;
119feadec63SPaolo Bonzini     DeleteCriticalSection(&mutex->lock);
120feadec63SPaolo Bonzini }
121feadec63SPaolo Bonzini 
qemu_rec_mutex_lock_impl(QemuRecMutex * mutex,const char * file,int line)122fe9959a2SEmilio G. Cota void qemu_rec_mutex_lock_impl(QemuRecMutex *mutex, const char *file, int line)
123feadec63SPaolo Bonzini {
124c096358eSFam Zheng     assert(mutex->initialized);
125feadec63SPaolo Bonzini     EnterCriticalSection(&mutex->lock);
126feadec63SPaolo Bonzini }
127feadec63SPaolo Bonzini 
qemu_rec_mutex_trylock_impl(QemuRecMutex * mutex,const char * file,int line)128fe9959a2SEmilio G. Cota int qemu_rec_mutex_trylock_impl(QemuRecMutex *mutex, const char *file, int line)
129feadec63SPaolo Bonzini {
130c096358eSFam Zheng     assert(mutex->initialized);
131feadec63SPaolo Bonzini     return !TryEnterCriticalSection(&mutex->lock);
132feadec63SPaolo Bonzini }
133feadec63SPaolo Bonzini 
qemu_rec_mutex_unlock_impl(QemuRecMutex * mutex,const char * file,int line)1349c75bae7SRichard Henderson void qemu_rec_mutex_unlock_impl(QemuRecMutex *mutex, const char *file, int line)
135feadec63SPaolo Bonzini {
136c096358eSFam Zheng     assert(mutex->initialized);
137feadec63SPaolo Bonzini     LeaveCriticalSection(&mutex->lock);
138feadec63SPaolo Bonzini }
139feadec63SPaolo Bonzini 
qemu_cond_init(QemuCond * cond)140baacf047SPaolo Bonzini void qemu_cond_init(QemuCond *cond)
141baacf047SPaolo Bonzini {
142baacf047SPaolo Bonzini     memset(cond, 0, sizeof(*cond));
14312f8def0SAndrey Shedel     InitializeConditionVariable(&cond->var);
144c096358eSFam Zheng     cond->initialized = true;
145baacf047SPaolo Bonzini }
146baacf047SPaolo Bonzini 
qemu_cond_destroy(QemuCond * cond)147baacf047SPaolo Bonzini void qemu_cond_destroy(QemuCond *cond)
148baacf047SPaolo Bonzini {
149c096358eSFam Zheng     assert(cond->initialized);
150c096358eSFam Zheng     cond->initialized = false;
15112f8def0SAndrey Shedel     InitializeConditionVariable(&cond->var);
152baacf047SPaolo Bonzini }
153baacf047SPaolo Bonzini 
qemu_cond_signal(QemuCond * cond)154baacf047SPaolo Bonzini void qemu_cond_signal(QemuCond *cond)
155baacf047SPaolo Bonzini {
156c096358eSFam Zheng     assert(cond->initialized);
15712f8def0SAndrey Shedel     WakeConditionVariable(&cond->var);
158baacf047SPaolo Bonzini }
159baacf047SPaolo Bonzini 
qemu_cond_broadcast(QemuCond * cond)160baacf047SPaolo Bonzini void qemu_cond_broadcast(QemuCond *cond)
161baacf047SPaolo Bonzini {
162c096358eSFam Zheng     assert(cond->initialized);
16312f8def0SAndrey Shedel     WakeAllConditionVariable(&cond->var);
164baacf047SPaolo Bonzini }
165baacf047SPaolo Bonzini 
qemu_cond_wait_impl(QemuCond * cond,QemuMutex * mutex,const char * file,const int line)1666c27a0deSAlex Bennée void qemu_cond_wait_impl(QemuCond *cond, QemuMutex *mutex, const char *file, const int line)
167baacf047SPaolo Bonzini {
168c096358eSFam Zheng     assert(cond->initialized);
169f1aff7aaSPeter Xu     qemu_mutex_pre_unlock(mutex, file, line);
17012f8def0SAndrey Shedel     SleepConditionVariableSRW(&cond->var, &mutex->lock, INFINITE, 0);
171f1aff7aaSPeter Xu     qemu_mutex_post_lock(mutex, file, line);
172baacf047SPaolo Bonzini }
173baacf047SPaolo Bonzini 
qemu_cond_timedwait_impl(QemuCond * cond,QemuMutex * mutex,int ms,const char * file,const int line)1743dcc9c6eSYury Kotov bool qemu_cond_timedwait_impl(QemuCond *cond, QemuMutex *mutex, int ms,
1753dcc9c6eSYury Kotov                               const char *file, const int line)
1763dcc9c6eSYury Kotov {
1773dcc9c6eSYury Kotov     int rc = 0;
1783dcc9c6eSYury Kotov 
1793dcc9c6eSYury Kotov     assert(cond->initialized);
1803dcc9c6eSYury Kotov     trace_qemu_mutex_unlock(mutex, file, line);
1813dcc9c6eSYury Kotov     if (!SleepConditionVariableSRW(&cond->var, &mutex->lock, ms, 0)) {
1823dcc9c6eSYury Kotov         rc = GetLastError();
1833dcc9c6eSYury Kotov     }
1843dcc9c6eSYury Kotov     trace_qemu_mutex_locked(mutex, file, line);
1853dcc9c6eSYury Kotov     if (rc && rc != ERROR_TIMEOUT) {
1863dcc9c6eSYury Kotov         error_exit(rc, __func__);
1873dcc9c6eSYury Kotov     }
1883dcc9c6eSYury Kotov     return rc != ERROR_TIMEOUT;
1893dcc9c6eSYury Kotov }
1903dcc9c6eSYury Kotov 
qemu_sem_init(QemuSemaphore * sem,int init)191baacf047SPaolo Bonzini void qemu_sem_init(QemuSemaphore *sem, int init)
192baacf047SPaolo Bonzini {
193baacf047SPaolo Bonzini     /* Manual reset.  */
194baacf047SPaolo Bonzini     sem->sema = CreateSemaphore(NULL, init, LONG_MAX, NULL);
195c096358eSFam Zheng     sem->initialized = true;
196baacf047SPaolo Bonzini }
197baacf047SPaolo Bonzini 
qemu_sem_destroy(QemuSemaphore * sem)198baacf047SPaolo Bonzini void qemu_sem_destroy(QemuSemaphore *sem)
199baacf047SPaolo Bonzini {
200c096358eSFam Zheng     assert(sem->initialized);
201c096358eSFam Zheng     sem->initialized = false;
202baacf047SPaolo Bonzini     CloseHandle(sem->sema);
203baacf047SPaolo Bonzini }
204baacf047SPaolo Bonzini 
qemu_sem_post(QemuSemaphore * sem)205baacf047SPaolo Bonzini void qemu_sem_post(QemuSemaphore *sem)
206baacf047SPaolo Bonzini {
207c096358eSFam Zheng     assert(sem->initialized);
208baacf047SPaolo Bonzini     ReleaseSemaphore(sem->sema, 1, NULL);
209baacf047SPaolo Bonzini }
210baacf047SPaolo Bonzini 
qemu_sem_timedwait(QemuSemaphore * sem,int ms)211baacf047SPaolo Bonzini int qemu_sem_timedwait(QemuSemaphore *sem, int ms)
212baacf047SPaolo Bonzini {
213c096358eSFam Zheng     int rc;
214c096358eSFam Zheng 
215c096358eSFam Zheng     assert(sem->initialized);
216c096358eSFam Zheng     rc = WaitForSingleObject(sem->sema, ms);
217baacf047SPaolo Bonzini     if (rc == WAIT_OBJECT_0) {
218baacf047SPaolo Bonzini         return 0;
219baacf047SPaolo Bonzini     }
220baacf047SPaolo Bonzini     if (rc != WAIT_TIMEOUT) {
221baacf047SPaolo Bonzini         error_exit(GetLastError(), __func__);
222baacf047SPaolo Bonzini     }
223baacf047SPaolo Bonzini     return -1;
224baacf047SPaolo Bonzini }
225baacf047SPaolo Bonzini 
qemu_sem_wait(QemuSemaphore * sem)226baacf047SPaolo Bonzini void qemu_sem_wait(QemuSemaphore *sem)
227baacf047SPaolo Bonzini {
228c096358eSFam Zheng     assert(sem->initialized);
229baacf047SPaolo Bonzini     if (WaitForSingleObject(sem->sema, INFINITE) != WAIT_OBJECT_0) {
230baacf047SPaolo Bonzini         error_exit(GetLastError(), __func__);
231baacf047SPaolo Bonzini     }
232baacf047SPaolo Bonzini }
233baacf047SPaolo Bonzini 
2347c9b2bf6SPaolo Bonzini /* Wrap a Win32 manual-reset event with a fast userspace path.  The idea
2357c9b2bf6SPaolo Bonzini  * is to reset the Win32 event lazily, as part of a test-reset-test-wait
2367c9b2bf6SPaolo Bonzini  * sequence.  Such a sequence is, indeed, how QemuEvents are used by
2377c9b2bf6SPaolo Bonzini  * RCU and other subsystems!
2387c9b2bf6SPaolo Bonzini  *
2397c9b2bf6SPaolo Bonzini  * Valid transitions:
2407c9b2bf6SPaolo Bonzini  * - free->set, when setting the event
241fbcc3e50SPaolo Bonzini  * - busy->set, when setting the event, followed by SetEvent
2427c9b2bf6SPaolo Bonzini  * - set->free, when resetting the event
2437c9b2bf6SPaolo Bonzini  * - free->busy, when waiting
2447c9b2bf6SPaolo Bonzini  *
2457c9b2bf6SPaolo Bonzini  * set->busy does not happen (it can be observed from the outside but
2467c9b2bf6SPaolo Bonzini  * it really is set->free->busy).
2477c9b2bf6SPaolo Bonzini  *
2487c9b2bf6SPaolo Bonzini  * busy->free provably cannot happen; to enforce it, the set->free transition
2497c9b2bf6SPaolo Bonzini  * is done with an OR, which becomes a no-op if the event has concurrently
2507c9b2bf6SPaolo Bonzini  * transitioned to free or busy (and is faster than cmpxchg).
2517c9b2bf6SPaolo Bonzini  */
2527c9b2bf6SPaolo Bonzini 
2537c9b2bf6SPaolo Bonzini #define EV_SET         0
2547c9b2bf6SPaolo Bonzini #define EV_FREE        1
2557c9b2bf6SPaolo Bonzini #define EV_BUSY       -1
2567c9b2bf6SPaolo Bonzini 
qemu_event_init(QemuEvent * ev,bool init)257c7c4d063SPaolo Bonzini void qemu_event_init(QemuEvent *ev, bool init)
258c7c4d063SPaolo Bonzini {
259c7c4d063SPaolo Bonzini     /* Manual reset.  */
2607c9b2bf6SPaolo Bonzini     ev->event = CreateEvent(NULL, TRUE, TRUE, NULL);
2617c9b2bf6SPaolo Bonzini     ev->value = (init ? EV_SET : EV_FREE);
262c096358eSFam Zheng     ev->initialized = true;
263c7c4d063SPaolo Bonzini }
264c7c4d063SPaolo Bonzini 
qemu_event_destroy(QemuEvent * ev)265c7c4d063SPaolo Bonzini void qemu_event_destroy(QemuEvent *ev)
266c7c4d063SPaolo Bonzini {
267c096358eSFam Zheng     assert(ev->initialized);
268c096358eSFam Zheng     ev->initialized = false;
269c7c4d063SPaolo Bonzini     CloseHandle(ev->event);
270c7c4d063SPaolo Bonzini }
271c7c4d063SPaolo Bonzini 
qemu_event_set(QemuEvent * ev)272c7c4d063SPaolo Bonzini void qemu_event_set(QemuEvent *ev)
273c7c4d063SPaolo Bonzini {
274c096358eSFam Zheng     assert(ev->initialized);
275*6c5df4b4SPaolo Bonzini 
276*6c5df4b4SPaolo Bonzini     /*
277*6c5df4b4SPaolo Bonzini      * Pairs with both qemu_event_reset() and qemu_event_wait().
278*6c5df4b4SPaolo Bonzini      *
279*6c5df4b4SPaolo Bonzini      * qemu_event_set has release semantics, but because it *loads*
280374293caSPaolo Bonzini      * ev->value we need a full memory barrier here.
281374293caSPaolo Bonzini      */
282374293caSPaolo Bonzini     smp_mb();
283d73415a3SStefan Hajnoczi     if (qatomic_read(&ev->value) != EV_SET) {
284*6c5df4b4SPaolo Bonzini         int old = qatomic_xchg(&ev->value, EV_SET);
285*6c5df4b4SPaolo Bonzini 
286*6c5df4b4SPaolo Bonzini         /* Pairs with memory barrier after ResetEvent.  */
287*6c5df4b4SPaolo Bonzini         smp_mb__after_rmw();
288*6c5df4b4SPaolo Bonzini         if (old == EV_BUSY) {
2897c9b2bf6SPaolo Bonzini             /* There were waiters, wake them up.  */
290c7c4d063SPaolo Bonzini             SetEvent(ev->event);
291c7c4d063SPaolo Bonzini         }
2927c9b2bf6SPaolo Bonzini     }
2937c9b2bf6SPaolo Bonzini }
294c7c4d063SPaolo Bonzini 
qemu_event_reset(QemuEvent * ev)295c7c4d063SPaolo Bonzini void qemu_event_reset(QemuEvent *ev)
296c7c4d063SPaolo Bonzini {
297c096358eSFam Zheng     assert(ev->initialized);
298*6c5df4b4SPaolo Bonzini 
299*6c5df4b4SPaolo Bonzini     /*
300*6c5df4b4SPaolo Bonzini      * If there was a concurrent reset (or even reset+wait),
3017c9b2bf6SPaolo Bonzini      * do nothing.  Otherwise change EV_SET->EV_FREE.
3027c9b2bf6SPaolo Bonzini      */
303d73415a3SStefan Hajnoczi     qatomic_or(&ev->value, EV_FREE);
304*6c5df4b4SPaolo Bonzini 
305*6c5df4b4SPaolo Bonzini     /*
306*6c5df4b4SPaolo Bonzini      * Order reset before checking the condition in the caller.
307*6c5df4b4SPaolo Bonzini      * Pairs with the first memory barrier in qemu_event_set().
308*6c5df4b4SPaolo Bonzini      */
309*6c5df4b4SPaolo Bonzini     smp_mb__after_rmw();
310c7c4d063SPaolo Bonzini }
311c7c4d063SPaolo Bonzini 
qemu_event_wait(QemuEvent * ev)312c7c4d063SPaolo Bonzini void qemu_event_wait(QemuEvent *ev)
313c7c4d063SPaolo Bonzini {
3147c9b2bf6SPaolo Bonzini     unsigned value;
3157c9b2bf6SPaolo Bonzini 
316c096358eSFam Zheng     assert(ev->initialized);
317*6c5df4b4SPaolo Bonzini 
318*6c5df4b4SPaolo Bonzini     /*
319*6c5df4b4SPaolo Bonzini      * qemu_event_wait must synchronize with qemu_event_set even if it does
320*6c5df4b4SPaolo Bonzini      * not go down the slow path, so this load-acquire is needed that
321*6c5df4b4SPaolo Bonzini      * synchronizes with the first memory barrier in qemu_event_set().
322*6c5df4b4SPaolo Bonzini      *
323*6c5df4b4SPaolo Bonzini      * If we do go down the slow path, there is no requirement at all: we
324*6c5df4b4SPaolo Bonzini      * might miss a qemu_event_set() here but ultimately the memory barrier in
325*6c5df4b4SPaolo Bonzini      * qemu_futex_wait() will ensure the check is done correctly.
326*6c5df4b4SPaolo Bonzini      */
327*6c5df4b4SPaolo Bonzini     value = qatomic_load_acquire(&ev->value);
3287c9b2bf6SPaolo Bonzini     if (value != EV_SET) {
3297c9b2bf6SPaolo Bonzini         if (value == EV_FREE) {
330*6c5df4b4SPaolo Bonzini             /*
331*6c5df4b4SPaolo Bonzini              * Here the underlying kernel event is reset, but qemu_event_set is
332*6c5df4b4SPaolo Bonzini              * not yet going to call SetEvent.  However, there will be another
333*6c5df4b4SPaolo Bonzini              * check for EV_SET below when setting EV_BUSY.  At that point it
334*6c5df4b4SPaolo Bonzini              * is safe to call WaitForSingleObject.
3357c9b2bf6SPaolo Bonzini              */
3367c9b2bf6SPaolo Bonzini             ResetEvent(ev->event);
3377c9b2bf6SPaolo Bonzini 
338*6c5df4b4SPaolo Bonzini             /*
339*6c5df4b4SPaolo Bonzini              * It is not clear whether ResetEvent provides this barrier; kernel
340*6c5df4b4SPaolo Bonzini              * APIs (KeResetEvent/KeClearEvent) do not.  Better safe than sorry!
341*6c5df4b4SPaolo Bonzini              */
342*6c5df4b4SPaolo Bonzini             smp_mb();
343*6c5df4b4SPaolo Bonzini 
344*6c5df4b4SPaolo Bonzini             /*
345*6c5df4b4SPaolo Bonzini              * Leave the event reset and tell qemu_event_set that there are
346*6c5df4b4SPaolo Bonzini              * waiters.  No need to retry, because there cannot be a concurrent
347*6c5df4b4SPaolo Bonzini              * busy->free transition.  After the CAS, the event will be either
348*6c5df4b4SPaolo Bonzini              * set or busy.
3497c9b2bf6SPaolo Bonzini              */
350d73415a3SStefan Hajnoczi             if (qatomic_cmpxchg(&ev->value, EV_FREE, EV_BUSY) == EV_SET) {
351*6c5df4b4SPaolo Bonzini                 return;
3527c9b2bf6SPaolo Bonzini             }
3537c9b2bf6SPaolo Bonzini         }
354*6c5df4b4SPaolo Bonzini 
355*6c5df4b4SPaolo Bonzini         /*
356*6c5df4b4SPaolo Bonzini          * ev->value is now EV_BUSY.  Since we didn't observe EV_SET,
357*6c5df4b4SPaolo Bonzini          * qemu_event_set() must observe EV_BUSY and call SetEvent().
358*6c5df4b4SPaolo Bonzini          */
359c7c4d063SPaolo Bonzini         WaitForSingleObject(ev->event, INFINITE);
360c7c4d063SPaolo Bonzini     }
3617c9b2bf6SPaolo Bonzini }
362c7c4d063SPaolo Bonzini 
363baacf047SPaolo Bonzini struct QemuThreadData {
364baacf047SPaolo Bonzini     /* Passed to win32_start_routine.  */
365baacf047SPaolo Bonzini     void             *(*start_routine)(void *);
366baacf047SPaolo Bonzini     void             *arg;
367baacf047SPaolo Bonzini     short             mode;
368ef57137fSPaolo Bonzini     NotifierList      exit;
369baacf047SPaolo Bonzini 
370baacf047SPaolo Bonzini     /* Only used for joinable threads. */
371baacf047SPaolo Bonzini     bool              exited;
372baacf047SPaolo Bonzini     void             *ret;
373baacf047SPaolo Bonzini     CRITICAL_SECTION  cs;
374baacf047SPaolo Bonzini };
375baacf047SPaolo Bonzini 
376ef57137fSPaolo Bonzini static bool atexit_registered;
377ef57137fSPaolo Bonzini static NotifierList main_thread_exit;
378ef57137fSPaolo Bonzini 
379baacf047SPaolo Bonzini static __thread QemuThreadData *qemu_thread_data;
380baacf047SPaolo Bonzini 
run_main_thread_exit(void)381ef57137fSPaolo Bonzini static void run_main_thread_exit(void)
382ef57137fSPaolo Bonzini {
383ef57137fSPaolo Bonzini     notifier_list_notify(&main_thread_exit, NULL);
384ef57137fSPaolo Bonzini }
385ef57137fSPaolo Bonzini 
qemu_thread_atexit_add(Notifier * notifier)386ef57137fSPaolo Bonzini void qemu_thread_atexit_add(Notifier *notifier)
387ef57137fSPaolo Bonzini {
388ef57137fSPaolo Bonzini     if (!qemu_thread_data) {
389ef57137fSPaolo Bonzini         if (!atexit_registered) {
390ef57137fSPaolo Bonzini             atexit_registered = true;
391ef57137fSPaolo Bonzini             atexit(run_main_thread_exit);
392ef57137fSPaolo Bonzini         }
393ef57137fSPaolo Bonzini         notifier_list_add(&main_thread_exit, notifier);
394ef57137fSPaolo Bonzini     } else {
395ef57137fSPaolo Bonzini         notifier_list_add(&qemu_thread_data->exit, notifier);
396ef57137fSPaolo Bonzini     }
397ef57137fSPaolo Bonzini }
398ef57137fSPaolo Bonzini 
qemu_thread_atexit_remove(Notifier * notifier)399ef57137fSPaolo Bonzini void qemu_thread_atexit_remove(Notifier *notifier)
400ef57137fSPaolo Bonzini {
401ef57137fSPaolo Bonzini     notifier_remove(notifier);
402ef57137fSPaolo Bonzini }
403ef57137fSPaolo Bonzini 
win32_start_routine(void * arg)404baacf047SPaolo Bonzini static unsigned __stdcall win32_start_routine(void *arg)
405baacf047SPaolo Bonzini {
406baacf047SPaolo Bonzini     QemuThreadData *data = (QemuThreadData *) arg;
407baacf047SPaolo Bonzini     void *(*start_routine)(void *) = data->start_routine;
408baacf047SPaolo Bonzini     void *thread_arg = data->arg;
409baacf047SPaolo Bonzini 
410baacf047SPaolo Bonzini     qemu_thread_data = data;
411baacf047SPaolo Bonzini     qemu_thread_exit(start_routine(thread_arg));
412baacf047SPaolo Bonzini     abort();
413baacf047SPaolo Bonzini }
414baacf047SPaolo Bonzini 
qemu_thread_exit(void * arg)415baacf047SPaolo Bonzini void qemu_thread_exit(void *arg)
416baacf047SPaolo Bonzini {
417baacf047SPaolo Bonzini     QemuThreadData *data = qemu_thread_data;
418baacf047SPaolo Bonzini 
419ef57137fSPaolo Bonzini     notifier_list_notify(&data->exit, NULL);
420ef57137fSPaolo Bonzini     if (data->mode == QEMU_THREAD_JOINABLE) {
421baacf047SPaolo Bonzini         data->ret = arg;
422baacf047SPaolo Bonzini         EnterCriticalSection(&data->cs);
423baacf047SPaolo Bonzini         data->exited = true;
424baacf047SPaolo Bonzini         LeaveCriticalSection(&data->cs);
425ef57137fSPaolo Bonzini     } else {
426ef57137fSPaolo Bonzini         g_free(data);
427baacf047SPaolo Bonzini     }
428baacf047SPaolo Bonzini     _endthreadex(0);
429baacf047SPaolo Bonzini }
430baacf047SPaolo Bonzini 
qemu_thread_join(QemuThread * thread)431baacf047SPaolo Bonzini void *qemu_thread_join(QemuThread *thread)
432baacf047SPaolo Bonzini {
433baacf047SPaolo Bonzini     QemuThreadData *data;
434baacf047SPaolo Bonzini     void *ret;
435baacf047SPaolo Bonzini     HANDLE handle;
436baacf047SPaolo Bonzini 
437baacf047SPaolo Bonzini     data = thread->data;
438ef57137fSPaolo Bonzini     if (data->mode == QEMU_THREAD_DETACHED) {
439baacf047SPaolo Bonzini         return NULL;
440baacf047SPaolo Bonzini     }
441ef57137fSPaolo Bonzini 
442baacf047SPaolo Bonzini     /*
443baacf047SPaolo Bonzini      * Because multiple copies of the QemuThread can exist via
444baacf047SPaolo Bonzini      * qemu_thread_get_self, we need to store a value that cannot
445baacf047SPaolo Bonzini      * leak there.  The simplest, non racy way is to store the TID,
446baacf047SPaolo Bonzini      * discard the handle that _beginthreadex gives back, and
447baacf047SPaolo Bonzini      * get another copy of the handle here.
448baacf047SPaolo Bonzini      */
449baacf047SPaolo Bonzini     handle = qemu_thread_get_handle(thread);
450baacf047SPaolo Bonzini     if (handle) {
451baacf047SPaolo Bonzini         WaitForSingleObject(handle, INFINITE);
452baacf047SPaolo Bonzini         CloseHandle(handle);
453baacf047SPaolo Bonzini     }
454baacf047SPaolo Bonzini     ret = data->ret;
455baacf047SPaolo Bonzini     DeleteCriticalSection(&data->cs);
456baacf047SPaolo Bonzini     g_free(data);
457baacf047SPaolo Bonzini     return ret;
458baacf047SPaolo Bonzini }
459baacf047SPaolo Bonzini 
set_thread_description(HANDLE h,const char * name)4604db99c9dSMarc-André Lureau static bool set_thread_description(HANDLE h, const char *name)
4614db99c9dSMarc-André Lureau {
4624db99c9dSMarc-André Lureau     HRESULT hr;
4634db99c9dSMarc-André Lureau     g_autofree wchar_t *namew = NULL;
4644db99c9dSMarc-André Lureau 
4654db99c9dSMarc-André Lureau     if (!load_set_thread_description()) {
4664db99c9dSMarc-André Lureau         return false;
4674db99c9dSMarc-André Lureau     }
4684db99c9dSMarc-André Lureau 
4694db99c9dSMarc-André Lureau     namew = g_utf8_to_utf16(name, -1, NULL, NULL, NULL);
4704db99c9dSMarc-André Lureau     if (!namew) {
4714db99c9dSMarc-André Lureau         return false;
4724db99c9dSMarc-André Lureau     }
4734db99c9dSMarc-André Lureau 
4744db99c9dSMarc-André Lureau     hr = SetThreadDescriptionFunc(h, namew);
4754db99c9dSMarc-André Lureau 
4764db99c9dSMarc-André Lureau     return SUCCEEDED(hr);
4774db99c9dSMarc-André Lureau }
4784db99c9dSMarc-André Lureau 
qemu_thread_create(QemuThread * thread,const char * name,void * (* start_routine)(void *),void * arg,int mode)4794900116eSDr. David Alan Gilbert void qemu_thread_create(QemuThread *thread, const char *name,
480baacf047SPaolo Bonzini                        void *(*start_routine)(void *),
481baacf047SPaolo Bonzini                        void *arg, int mode)
482baacf047SPaolo Bonzini {
483baacf047SPaolo Bonzini     HANDLE hThread;
484baacf047SPaolo Bonzini     struct QemuThreadData *data;
485baacf047SPaolo Bonzini 
486baacf047SPaolo Bonzini     data = g_malloc(sizeof *data);
487baacf047SPaolo Bonzini     data->start_routine = start_routine;
488baacf047SPaolo Bonzini     data->arg = arg;
489baacf047SPaolo Bonzini     data->mode = mode;
490baacf047SPaolo Bonzini     data->exited = false;
491ef57137fSPaolo Bonzini     notifier_list_init(&data->exit);
492baacf047SPaolo Bonzini 
493baacf047SPaolo Bonzini     if (data->mode != QEMU_THREAD_DETACHED) {
494baacf047SPaolo Bonzini         InitializeCriticalSection(&data->cs);
495baacf047SPaolo Bonzini     }
496baacf047SPaolo Bonzini 
497baacf047SPaolo Bonzini     hThread = (HANDLE) _beginthreadex(NULL, 0, win32_start_routine,
498baacf047SPaolo Bonzini                                       data, 0, &thread->tid);
499baacf047SPaolo Bonzini     if (!hThread) {
500baacf047SPaolo Bonzini         error_exit(GetLastError(), __func__);
501baacf047SPaolo Bonzini     }
5024db99c9dSMarc-André Lureau     if (name_threads && name && !set_thread_description(hThread, name)) {
5034db99c9dSMarc-André Lureau         fprintf(stderr, "qemu: failed to set thread description: %s\n", name);
5044db99c9dSMarc-André Lureau     }
505baacf047SPaolo Bonzini     CloseHandle(hThread);
5064db99c9dSMarc-André Lureau 
507ef57137fSPaolo Bonzini     thread->data = data;
508baacf047SPaolo Bonzini }
509baacf047SPaolo Bonzini 
qemu_thread_set_affinity(QemuThread * thread,unsigned long * host_cpus,unsigned long nbits)5107730f32cSDavid Hildenbrand int qemu_thread_set_affinity(QemuThread *thread, unsigned long *host_cpus,
5117730f32cSDavid Hildenbrand                              unsigned long nbits)
5127730f32cSDavid Hildenbrand {
5137730f32cSDavid Hildenbrand     return -ENOSYS;
5147730f32cSDavid Hildenbrand }
5157730f32cSDavid Hildenbrand 
qemu_thread_get_affinity(QemuThread * thread,unsigned long ** host_cpus,unsigned long * nbits)5167730f32cSDavid Hildenbrand int qemu_thread_get_affinity(QemuThread *thread, unsigned long **host_cpus,
5177730f32cSDavid Hildenbrand                              unsigned long *nbits)
5187730f32cSDavid Hildenbrand {
5197730f32cSDavid Hildenbrand     return -ENOSYS;
5207730f32cSDavid Hildenbrand }
5217730f32cSDavid Hildenbrand 
qemu_thread_get_self(QemuThread * thread)522baacf047SPaolo Bonzini void qemu_thread_get_self(QemuThread *thread)
523baacf047SPaolo Bonzini {
524baacf047SPaolo Bonzini     thread->data = qemu_thread_data;
525baacf047SPaolo Bonzini     thread->tid = GetCurrentThreadId();
526baacf047SPaolo Bonzini }
527baacf047SPaolo Bonzini 
qemu_thread_get_handle(QemuThread * thread)528baacf047SPaolo Bonzini HANDLE qemu_thread_get_handle(QemuThread *thread)
529baacf047SPaolo Bonzini {
530baacf047SPaolo Bonzini     QemuThreadData *data;
531baacf047SPaolo Bonzini     HANDLE handle;
532baacf047SPaolo Bonzini 
533baacf047SPaolo Bonzini     data = thread->data;
534ef57137fSPaolo Bonzini     if (data->mode == QEMU_THREAD_DETACHED) {
535baacf047SPaolo Bonzini         return NULL;
536baacf047SPaolo Bonzini     }
537baacf047SPaolo Bonzini 
538baacf047SPaolo Bonzini     EnterCriticalSection(&data->cs);
539baacf047SPaolo Bonzini     if (!data->exited) {
540b0cb0a66SVincent Palatin         handle = OpenThread(SYNCHRONIZE | THREAD_SUSPEND_RESUME |
541b0cb0a66SVincent Palatin                             THREAD_SET_CONTEXT, FALSE, thread->tid);
542baacf047SPaolo Bonzini     } else {
543baacf047SPaolo Bonzini         handle = NULL;
544baacf047SPaolo Bonzini     }
545baacf047SPaolo Bonzini     LeaveCriticalSection(&data->cs);
546baacf047SPaolo Bonzini     return handle;
547baacf047SPaolo Bonzini }
548baacf047SPaolo Bonzini 
qemu_thread_is_self(QemuThread * thread)549baacf047SPaolo Bonzini bool qemu_thread_is_self(QemuThread *thread)
550baacf047SPaolo Bonzini {
551baacf047SPaolo Bonzini     return GetCurrentThreadId() == thread->tid;
552baacf047SPaolo Bonzini }
553