xref: /openbmc/qemu/util/qemu-thread-win32.c (revision 9c75bae7)
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-common.h"
16baacf047SPaolo Bonzini #include "qemu/thread.h"
17ef57137fSPaolo Bonzini #include "qemu/notify.h"
18f1aff7aaSPeter Xu #include "qemu-thread-common.h"
19baacf047SPaolo Bonzini #include <process.h>
20baacf047SPaolo Bonzini 
218f480de0SDr. David Alan Gilbert static bool name_threads;
228f480de0SDr. David Alan Gilbert 
238f480de0SDr. David Alan Gilbert void qemu_thread_naming(bool enable)
248f480de0SDr. David Alan Gilbert {
258f480de0SDr. David Alan Gilbert     /* But note we don't actually name them on Windows yet */
268f480de0SDr. David Alan Gilbert     name_threads = enable;
275c312079SDr. David Alan Gilbert 
285c312079SDr. David Alan Gilbert     fprintf(stderr, "qemu: thread naming not supported on this host\n");
298f480de0SDr. David Alan Gilbert }
308f480de0SDr. David Alan Gilbert 
31baacf047SPaolo Bonzini static void error_exit(int err, const char *msg)
32baacf047SPaolo Bonzini {
33baacf047SPaolo Bonzini     char *pstr;
34baacf047SPaolo Bonzini 
35baacf047SPaolo Bonzini     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
36baacf047SPaolo Bonzini                   NULL, err, 0, (LPTSTR)&pstr, 2, NULL);
37baacf047SPaolo Bonzini     fprintf(stderr, "qemu: %s: %s\n", msg, pstr);
38baacf047SPaolo Bonzini     LocalFree(pstr);
39baacf047SPaolo Bonzini     abort();
40baacf047SPaolo Bonzini }
41baacf047SPaolo Bonzini 
42baacf047SPaolo Bonzini void qemu_mutex_init(QemuMutex *mutex)
43baacf047SPaolo Bonzini {
4412f8def0SAndrey Shedel     InitializeSRWLock(&mutex->lock);
45f1aff7aaSPeter Xu     qemu_mutex_post_init(mutex);
46baacf047SPaolo Bonzini }
47baacf047SPaolo Bonzini 
48baacf047SPaolo Bonzini void qemu_mutex_destroy(QemuMutex *mutex)
49baacf047SPaolo Bonzini {
50c096358eSFam Zheng     assert(mutex->initialized);
51c096358eSFam Zheng     mutex->initialized = false;
5212f8def0SAndrey Shedel     InitializeSRWLock(&mutex->lock);
53baacf047SPaolo Bonzini }
54baacf047SPaolo Bonzini 
556c27a0deSAlex Bennée void qemu_mutex_lock_impl(QemuMutex *mutex, const char *file, const int line)
56baacf047SPaolo Bonzini {
57c096358eSFam Zheng     assert(mutex->initialized);
58f1aff7aaSPeter Xu     qemu_mutex_pre_lock(mutex, file, line);
5912f8def0SAndrey Shedel     AcquireSRWLockExclusive(&mutex->lock);
60f1aff7aaSPeter Xu     qemu_mutex_post_lock(mutex, file, line);
61baacf047SPaolo Bonzini }
62baacf047SPaolo Bonzini 
636c27a0deSAlex Bennée int qemu_mutex_trylock_impl(QemuMutex *mutex, const char *file, const int line)
64baacf047SPaolo Bonzini {
65baacf047SPaolo Bonzini     int owned;
66baacf047SPaolo Bonzini 
67c096358eSFam Zheng     assert(mutex->initialized);
6812f8def0SAndrey Shedel     owned = TryAcquireSRWLockExclusive(&mutex->lock);
6931f5a726SJose Ricardo Ziviani     if (owned) {
70f1aff7aaSPeter Xu         qemu_mutex_post_lock(mutex, file, line);
7131f5a726SJose Ricardo Ziviani         return 0;
7231f5a726SJose Ricardo Ziviani     }
7331f5a726SJose Ricardo Ziviani     return -EBUSY;
74baacf047SPaolo Bonzini }
75baacf047SPaolo Bonzini 
766c27a0deSAlex Bennée void qemu_mutex_unlock_impl(QemuMutex *mutex, const char *file, const int line)
77baacf047SPaolo Bonzini {
78c096358eSFam Zheng     assert(mutex->initialized);
79f1aff7aaSPeter Xu     qemu_mutex_pre_unlock(mutex, file, line);
8012f8def0SAndrey Shedel     ReleaseSRWLockExclusive(&mutex->lock);
81baacf047SPaolo Bonzini }
82baacf047SPaolo Bonzini 
83feadec63SPaolo Bonzini void qemu_rec_mutex_init(QemuRecMutex *mutex)
84feadec63SPaolo Bonzini {
85feadec63SPaolo Bonzini     InitializeCriticalSection(&mutex->lock);
86c096358eSFam Zheng     mutex->initialized = true;
87feadec63SPaolo Bonzini }
88feadec63SPaolo Bonzini 
89feadec63SPaolo Bonzini void qemu_rec_mutex_destroy(QemuRecMutex *mutex)
90feadec63SPaolo Bonzini {
91c096358eSFam Zheng     assert(mutex->initialized);
92c096358eSFam Zheng     mutex->initialized = false;
93feadec63SPaolo Bonzini     DeleteCriticalSection(&mutex->lock);
94feadec63SPaolo Bonzini }
95feadec63SPaolo Bonzini 
96fe9959a2SEmilio G. Cota void qemu_rec_mutex_lock_impl(QemuRecMutex *mutex, const char *file, int line)
97feadec63SPaolo Bonzini {
98c096358eSFam Zheng     assert(mutex->initialized);
99feadec63SPaolo Bonzini     EnterCriticalSection(&mutex->lock);
100feadec63SPaolo Bonzini }
101feadec63SPaolo Bonzini 
102fe9959a2SEmilio G. Cota int qemu_rec_mutex_trylock_impl(QemuRecMutex *mutex, const char *file, int line)
103feadec63SPaolo Bonzini {
104c096358eSFam Zheng     assert(mutex->initialized);
105feadec63SPaolo Bonzini     return !TryEnterCriticalSection(&mutex->lock);
106feadec63SPaolo Bonzini }
107feadec63SPaolo Bonzini 
108*9c75bae7SRichard Henderson void qemu_rec_mutex_unlock_impl(QemuRecMutex *mutex, const char *file, int line)
109feadec63SPaolo Bonzini {
110c096358eSFam Zheng     assert(mutex->initialized);
111feadec63SPaolo Bonzini     LeaveCriticalSection(&mutex->lock);
112feadec63SPaolo Bonzini }
113feadec63SPaolo Bonzini 
114baacf047SPaolo Bonzini void qemu_cond_init(QemuCond *cond)
115baacf047SPaolo Bonzini {
116baacf047SPaolo Bonzini     memset(cond, 0, sizeof(*cond));
11712f8def0SAndrey Shedel     InitializeConditionVariable(&cond->var);
118c096358eSFam Zheng     cond->initialized = true;
119baacf047SPaolo Bonzini }
120baacf047SPaolo Bonzini 
121baacf047SPaolo Bonzini void qemu_cond_destroy(QemuCond *cond)
122baacf047SPaolo Bonzini {
123c096358eSFam Zheng     assert(cond->initialized);
124c096358eSFam Zheng     cond->initialized = false;
12512f8def0SAndrey Shedel     InitializeConditionVariable(&cond->var);
126baacf047SPaolo Bonzini }
127baacf047SPaolo Bonzini 
128baacf047SPaolo Bonzini void qemu_cond_signal(QemuCond *cond)
129baacf047SPaolo Bonzini {
130c096358eSFam Zheng     assert(cond->initialized);
13112f8def0SAndrey Shedel     WakeConditionVariable(&cond->var);
132baacf047SPaolo Bonzini }
133baacf047SPaolo Bonzini 
134baacf047SPaolo Bonzini void qemu_cond_broadcast(QemuCond *cond)
135baacf047SPaolo Bonzini {
136c096358eSFam Zheng     assert(cond->initialized);
13712f8def0SAndrey Shedel     WakeAllConditionVariable(&cond->var);
138baacf047SPaolo Bonzini }
139baacf047SPaolo Bonzini 
1406c27a0deSAlex Bennée void qemu_cond_wait_impl(QemuCond *cond, QemuMutex *mutex, const char *file, const int line)
141baacf047SPaolo Bonzini {
142c096358eSFam Zheng     assert(cond->initialized);
143f1aff7aaSPeter Xu     qemu_mutex_pre_unlock(mutex, file, line);
14412f8def0SAndrey Shedel     SleepConditionVariableSRW(&cond->var, &mutex->lock, INFINITE, 0);
145f1aff7aaSPeter Xu     qemu_mutex_post_lock(mutex, file, line);
146baacf047SPaolo Bonzini }
147baacf047SPaolo Bonzini 
1483dcc9c6eSYury Kotov bool qemu_cond_timedwait_impl(QemuCond *cond, QemuMutex *mutex, int ms,
1493dcc9c6eSYury Kotov                               const char *file, const int line)
1503dcc9c6eSYury Kotov {
1513dcc9c6eSYury Kotov     int rc = 0;
1523dcc9c6eSYury Kotov 
1533dcc9c6eSYury Kotov     assert(cond->initialized);
1543dcc9c6eSYury Kotov     trace_qemu_mutex_unlock(mutex, file, line);
1553dcc9c6eSYury Kotov     if (!SleepConditionVariableSRW(&cond->var, &mutex->lock, ms, 0)) {
1563dcc9c6eSYury Kotov         rc = GetLastError();
1573dcc9c6eSYury Kotov     }
1583dcc9c6eSYury Kotov     trace_qemu_mutex_locked(mutex, file, line);
1593dcc9c6eSYury Kotov     if (rc && rc != ERROR_TIMEOUT) {
1603dcc9c6eSYury Kotov         error_exit(rc, __func__);
1613dcc9c6eSYury Kotov     }
1623dcc9c6eSYury Kotov     return rc != ERROR_TIMEOUT;
1633dcc9c6eSYury Kotov }
1643dcc9c6eSYury Kotov 
165baacf047SPaolo Bonzini void qemu_sem_init(QemuSemaphore *sem, int init)
166baacf047SPaolo Bonzini {
167baacf047SPaolo Bonzini     /* Manual reset.  */
168baacf047SPaolo Bonzini     sem->sema = CreateSemaphore(NULL, init, LONG_MAX, NULL);
169c096358eSFam Zheng     sem->initialized = true;
170baacf047SPaolo Bonzini }
171baacf047SPaolo Bonzini 
172baacf047SPaolo Bonzini void qemu_sem_destroy(QemuSemaphore *sem)
173baacf047SPaolo Bonzini {
174c096358eSFam Zheng     assert(sem->initialized);
175c096358eSFam Zheng     sem->initialized = false;
176baacf047SPaolo Bonzini     CloseHandle(sem->sema);
177baacf047SPaolo Bonzini }
178baacf047SPaolo Bonzini 
179baacf047SPaolo Bonzini void qemu_sem_post(QemuSemaphore *sem)
180baacf047SPaolo Bonzini {
181c096358eSFam Zheng     assert(sem->initialized);
182baacf047SPaolo Bonzini     ReleaseSemaphore(sem->sema, 1, NULL);
183baacf047SPaolo Bonzini }
184baacf047SPaolo Bonzini 
185baacf047SPaolo Bonzini int qemu_sem_timedwait(QemuSemaphore *sem, int ms)
186baacf047SPaolo Bonzini {
187c096358eSFam Zheng     int rc;
188c096358eSFam Zheng 
189c096358eSFam Zheng     assert(sem->initialized);
190c096358eSFam Zheng     rc = WaitForSingleObject(sem->sema, ms);
191baacf047SPaolo Bonzini     if (rc == WAIT_OBJECT_0) {
192baacf047SPaolo Bonzini         return 0;
193baacf047SPaolo Bonzini     }
194baacf047SPaolo Bonzini     if (rc != WAIT_TIMEOUT) {
195baacf047SPaolo Bonzini         error_exit(GetLastError(), __func__);
196baacf047SPaolo Bonzini     }
197baacf047SPaolo Bonzini     return -1;
198baacf047SPaolo Bonzini }
199baacf047SPaolo Bonzini 
200baacf047SPaolo Bonzini void qemu_sem_wait(QemuSemaphore *sem)
201baacf047SPaolo Bonzini {
202c096358eSFam Zheng     assert(sem->initialized);
203baacf047SPaolo Bonzini     if (WaitForSingleObject(sem->sema, INFINITE) != WAIT_OBJECT_0) {
204baacf047SPaolo Bonzini         error_exit(GetLastError(), __func__);
205baacf047SPaolo Bonzini     }
206baacf047SPaolo Bonzini }
207baacf047SPaolo Bonzini 
2087c9b2bf6SPaolo Bonzini /* Wrap a Win32 manual-reset event with a fast userspace path.  The idea
2097c9b2bf6SPaolo Bonzini  * is to reset the Win32 event lazily, as part of a test-reset-test-wait
2107c9b2bf6SPaolo Bonzini  * sequence.  Such a sequence is, indeed, how QemuEvents are used by
2117c9b2bf6SPaolo Bonzini  * RCU and other subsystems!
2127c9b2bf6SPaolo Bonzini  *
2137c9b2bf6SPaolo Bonzini  * Valid transitions:
2147c9b2bf6SPaolo Bonzini  * - free->set, when setting the event
215fbcc3e50SPaolo Bonzini  * - busy->set, when setting the event, followed by SetEvent
2167c9b2bf6SPaolo Bonzini  * - set->free, when resetting the event
2177c9b2bf6SPaolo Bonzini  * - free->busy, when waiting
2187c9b2bf6SPaolo Bonzini  *
2197c9b2bf6SPaolo Bonzini  * set->busy does not happen (it can be observed from the outside but
2207c9b2bf6SPaolo Bonzini  * it really is set->free->busy).
2217c9b2bf6SPaolo Bonzini  *
2227c9b2bf6SPaolo Bonzini  * busy->free provably cannot happen; to enforce it, the set->free transition
2237c9b2bf6SPaolo Bonzini  * is done with an OR, which becomes a no-op if the event has concurrently
2247c9b2bf6SPaolo Bonzini  * transitioned to free or busy (and is faster than cmpxchg).
2257c9b2bf6SPaolo Bonzini  */
2267c9b2bf6SPaolo Bonzini 
2277c9b2bf6SPaolo Bonzini #define EV_SET         0
2287c9b2bf6SPaolo Bonzini #define EV_FREE        1
2297c9b2bf6SPaolo Bonzini #define EV_BUSY       -1
2307c9b2bf6SPaolo Bonzini 
231c7c4d063SPaolo Bonzini void qemu_event_init(QemuEvent *ev, bool init)
232c7c4d063SPaolo Bonzini {
233c7c4d063SPaolo Bonzini     /* Manual reset.  */
2347c9b2bf6SPaolo Bonzini     ev->event = CreateEvent(NULL, TRUE, TRUE, NULL);
2357c9b2bf6SPaolo Bonzini     ev->value = (init ? EV_SET : EV_FREE);
236c096358eSFam Zheng     ev->initialized = true;
237c7c4d063SPaolo Bonzini }
238c7c4d063SPaolo Bonzini 
239c7c4d063SPaolo Bonzini void qemu_event_destroy(QemuEvent *ev)
240c7c4d063SPaolo Bonzini {
241c096358eSFam Zheng     assert(ev->initialized);
242c096358eSFam Zheng     ev->initialized = false;
243c7c4d063SPaolo Bonzini     CloseHandle(ev->event);
244c7c4d063SPaolo Bonzini }
245c7c4d063SPaolo Bonzini 
246c7c4d063SPaolo Bonzini void qemu_event_set(QemuEvent *ev)
247c7c4d063SPaolo Bonzini {
248c096358eSFam Zheng     assert(ev->initialized);
249374293caSPaolo Bonzini     /* qemu_event_set has release semantics, but because it *loads*
250374293caSPaolo Bonzini      * ev->value we need a full memory barrier here.
251374293caSPaolo Bonzini      */
252374293caSPaolo Bonzini     smp_mb();
253d73415a3SStefan Hajnoczi     if (qatomic_read(&ev->value) != EV_SET) {
254d73415a3SStefan Hajnoczi         if (qatomic_xchg(&ev->value, EV_SET) == EV_BUSY) {
2557c9b2bf6SPaolo Bonzini             /* There were waiters, wake them up.  */
256c7c4d063SPaolo Bonzini             SetEvent(ev->event);
257c7c4d063SPaolo Bonzini         }
2587c9b2bf6SPaolo Bonzini     }
2597c9b2bf6SPaolo Bonzini }
260c7c4d063SPaolo Bonzini 
261c7c4d063SPaolo Bonzini void qemu_event_reset(QemuEvent *ev)
262c7c4d063SPaolo Bonzini {
263374293caSPaolo Bonzini     unsigned value;
264374293caSPaolo Bonzini 
265c096358eSFam Zheng     assert(ev->initialized);
266d73415a3SStefan Hajnoczi     value = qatomic_read(&ev->value);
267374293caSPaolo Bonzini     smp_mb_acquire();
268374293caSPaolo Bonzini     if (value == EV_SET) {
2697c9b2bf6SPaolo Bonzini         /* If there was a concurrent reset (or even reset+wait),
2707c9b2bf6SPaolo Bonzini          * do nothing.  Otherwise change EV_SET->EV_FREE.
2717c9b2bf6SPaolo Bonzini          */
272d73415a3SStefan Hajnoczi         qatomic_or(&ev->value, EV_FREE);
2737c9b2bf6SPaolo Bonzini     }
274c7c4d063SPaolo Bonzini }
275c7c4d063SPaolo Bonzini 
276c7c4d063SPaolo Bonzini void qemu_event_wait(QemuEvent *ev)
277c7c4d063SPaolo Bonzini {
2787c9b2bf6SPaolo Bonzini     unsigned value;
2797c9b2bf6SPaolo Bonzini 
280c096358eSFam Zheng     assert(ev->initialized);
281d73415a3SStefan Hajnoczi     value = qatomic_read(&ev->value);
282374293caSPaolo Bonzini     smp_mb_acquire();
2837c9b2bf6SPaolo Bonzini     if (value != EV_SET) {
2847c9b2bf6SPaolo Bonzini         if (value == EV_FREE) {
2857c9b2bf6SPaolo Bonzini             /* qemu_event_set is not yet going to call SetEvent, but we are
2867c9b2bf6SPaolo Bonzini              * going to do another check for EV_SET below when setting EV_BUSY.
2877c9b2bf6SPaolo Bonzini              * At that point it is safe to call WaitForSingleObject.
2887c9b2bf6SPaolo Bonzini              */
2897c9b2bf6SPaolo Bonzini             ResetEvent(ev->event);
2907c9b2bf6SPaolo Bonzini 
2917c9b2bf6SPaolo Bonzini             /* Tell qemu_event_set that there are waiters.  No need to retry
2928cc360b9Szhaolichang              * because there cannot be a concurrent busy->free transition.
2937c9b2bf6SPaolo Bonzini              * After the CAS, the event will be either set or busy.
2947c9b2bf6SPaolo Bonzini              */
295d73415a3SStefan Hajnoczi             if (qatomic_cmpxchg(&ev->value, EV_FREE, EV_BUSY) == EV_SET) {
2967c9b2bf6SPaolo Bonzini                 value = EV_SET;
2977c9b2bf6SPaolo Bonzini             } else {
2987c9b2bf6SPaolo Bonzini                 value = EV_BUSY;
2997c9b2bf6SPaolo Bonzini             }
3007c9b2bf6SPaolo Bonzini         }
3017c9b2bf6SPaolo Bonzini         if (value == EV_BUSY) {
302c7c4d063SPaolo Bonzini             WaitForSingleObject(ev->event, INFINITE);
303c7c4d063SPaolo Bonzini         }
3047c9b2bf6SPaolo Bonzini     }
3057c9b2bf6SPaolo Bonzini }
306c7c4d063SPaolo Bonzini 
307baacf047SPaolo Bonzini struct QemuThreadData {
308baacf047SPaolo Bonzini     /* Passed to win32_start_routine.  */
309baacf047SPaolo Bonzini     void             *(*start_routine)(void *);
310baacf047SPaolo Bonzini     void             *arg;
311baacf047SPaolo Bonzini     short             mode;
312ef57137fSPaolo Bonzini     NotifierList      exit;
313baacf047SPaolo Bonzini 
314baacf047SPaolo Bonzini     /* Only used for joinable threads. */
315baacf047SPaolo Bonzini     bool              exited;
316baacf047SPaolo Bonzini     void             *ret;
317baacf047SPaolo Bonzini     CRITICAL_SECTION  cs;
318baacf047SPaolo Bonzini };
319baacf047SPaolo Bonzini 
320ef57137fSPaolo Bonzini static bool atexit_registered;
321ef57137fSPaolo Bonzini static NotifierList main_thread_exit;
322ef57137fSPaolo Bonzini 
323baacf047SPaolo Bonzini static __thread QemuThreadData *qemu_thread_data;
324baacf047SPaolo Bonzini 
325ef57137fSPaolo Bonzini static void run_main_thread_exit(void)
326ef57137fSPaolo Bonzini {
327ef57137fSPaolo Bonzini     notifier_list_notify(&main_thread_exit, NULL);
328ef57137fSPaolo Bonzini }
329ef57137fSPaolo Bonzini 
330ef57137fSPaolo Bonzini void qemu_thread_atexit_add(Notifier *notifier)
331ef57137fSPaolo Bonzini {
332ef57137fSPaolo Bonzini     if (!qemu_thread_data) {
333ef57137fSPaolo Bonzini         if (!atexit_registered) {
334ef57137fSPaolo Bonzini             atexit_registered = true;
335ef57137fSPaolo Bonzini             atexit(run_main_thread_exit);
336ef57137fSPaolo Bonzini         }
337ef57137fSPaolo Bonzini         notifier_list_add(&main_thread_exit, notifier);
338ef57137fSPaolo Bonzini     } else {
339ef57137fSPaolo Bonzini         notifier_list_add(&qemu_thread_data->exit, notifier);
340ef57137fSPaolo Bonzini     }
341ef57137fSPaolo Bonzini }
342ef57137fSPaolo Bonzini 
343ef57137fSPaolo Bonzini void qemu_thread_atexit_remove(Notifier *notifier)
344ef57137fSPaolo Bonzini {
345ef57137fSPaolo Bonzini     notifier_remove(notifier);
346ef57137fSPaolo Bonzini }
347ef57137fSPaolo Bonzini 
348baacf047SPaolo Bonzini static unsigned __stdcall win32_start_routine(void *arg)
349baacf047SPaolo Bonzini {
350baacf047SPaolo Bonzini     QemuThreadData *data = (QemuThreadData *) arg;
351baacf047SPaolo Bonzini     void *(*start_routine)(void *) = data->start_routine;
352baacf047SPaolo Bonzini     void *thread_arg = data->arg;
353baacf047SPaolo Bonzini 
354baacf047SPaolo Bonzini     qemu_thread_data = data;
355baacf047SPaolo Bonzini     qemu_thread_exit(start_routine(thread_arg));
356baacf047SPaolo Bonzini     abort();
357baacf047SPaolo Bonzini }
358baacf047SPaolo Bonzini 
359baacf047SPaolo Bonzini void qemu_thread_exit(void *arg)
360baacf047SPaolo Bonzini {
361baacf047SPaolo Bonzini     QemuThreadData *data = qemu_thread_data;
362baacf047SPaolo Bonzini 
363ef57137fSPaolo Bonzini     notifier_list_notify(&data->exit, NULL);
364ef57137fSPaolo Bonzini     if (data->mode == QEMU_THREAD_JOINABLE) {
365baacf047SPaolo Bonzini         data->ret = arg;
366baacf047SPaolo Bonzini         EnterCriticalSection(&data->cs);
367baacf047SPaolo Bonzini         data->exited = true;
368baacf047SPaolo Bonzini         LeaveCriticalSection(&data->cs);
369ef57137fSPaolo Bonzini     } else {
370ef57137fSPaolo Bonzini         g_free(data);
371baacf047SPaolo Bonzini     }
372baacf047SPaolo Bonzini     _endthreadex(0);
373baacf047SPaolo Bonzini }
374baacf047SPaolo Bonzini 
375baacf047SPaolo Bonzini void *qemu_thread_join(QemuThread *thread)
376baacf047SPaolo Bonzini {
377baacf047SPaolo Bonzini     QemuThreadData *data;
378baacf047SPaolo Bonzini     void *ret;
379baacf047SPaolo Bonzini     HANDLE handle;
380baacf047SPaolo Bonzini 
381baacf047SPaolo Bonzini     data = thread->data;
382ef57137fSPaolo Bonzini     if (data->mode == QEMU_THREAD_DETACHED) {
383baacf047SPaolo Bonzini         return NULL;
384baacf047SPaolo Bonzini     }
385ef57137fSPaolo Bonzini 
386baacf047SPaolo Bonzini     /*
387baacf047SPaolo Bonzini      * Because multiple copies of the QemuThread can exist via
388baacf047SPaolo Bonzini      * qemu_thread_get_self, we need to store a value that cannot
389baacf047SPaolo Bonzini      * leak there.  The simplest, non racy way is to store the TID,
390baacf047SPaolo Bonzini      * discard the handle that _beginthreadex gives back, and
391baacf047SPaolo Bonzini      * get another copy of the handle here.
392baacf047SPaolo Bonzini      */
393baacf047SPaolo Bonzini     handle = qemu_thread_get_handle(thread);
394baacf047SPaolo Bonzini     if (handle) {
395baacf047SPaolo Bonzini         WaitForSingleObject(handle, INFINITE);
396baacf047SPaolo Bonzini         CloseHandle(handle);
397baacf047SPaolo Bonzini     }
398baacf047SPaolo Bonzini     ret = data->ret;
399baacf047SPaolo Bonzini     DeleteCriticalSection(&data->cs);
400baacf047SPaolo Bonzini     g_free(data);
401baacf047SPaolo Bonzini     return ret;
402baacf047SPaolo Bonzini }
403baacf047SPaolo Bonzini 
4044900116eSDr. David Alan Gilbert void qemu_thread_create(QemuThread *thread, const char *name,
405baacf047SPaolo Bonzini                        void *(*start_routine)(void *),
406baacf047SPaolo Bonzini                        void *arg, int mode)
407baacf047SPaolo Bonzini {
408baacf047SPaolo Bonzini     HANDLE hThread;
409baacf047SPaolo Bonzini     struct QemuThreadData *data;
410baacf047SPaolo Bonzini 
411baacf047SPaolo Bonzini     data = g_malloc(sizeof *data);
412baacf047SPaolo Bonzini     data->start_routine = start_routine;
413baacf047SPaolo Bonzini     data->arg = arg;
414baacf047SPaolo Bonzini     data->mode = mode;
415baacf047SPaolo Bonzini     data->exited = false;
416ef57137fSPaolo Bonzini     notifier_list_init(&data->exit);
417baacf047SPaolo Bonzini 
418baacf047SPaolo Bonzini     if (data->mode != QEMU_THREAD_DETACHED) {
419baacf047SPaolo Bonzini         InitializeCriticalSection(&data->cs);
420baacf047SPaolo Bonzini     }
421baacf047SPaolo Bonzini 
422baacf047SPaolo Bonzini     hThread = (HANDLE) _beginthreadex(NULL, 0, win32_start_routine,
423baacf047SPaolo Bonzini                                       data, 0, &thread->tid);
424baacf047SPaolo Bonzini     if (!hThread) {
425baacf047SPaolo Bonzini         error_exit(GetLastError(), __func__);
426baacf047SPaolo Bonzini     }
427baacf047SPaolo Bonzini     CloseHandle(hThread);
428ef57137fSPaolo Bonzini     thread->data = data;
429baacf047SPaolo Bonzini }
430baacf047SPaolo Bonzini 
431baacf047SPaolo Bonzini void qemu_thread_get_self(QemuThread *thread)
432baacf047SPaolo Bonzini {
433baacf047SPaolo Bonzini     thread->data = qemu_thread_data;
434baacf047SPaolo Bonzini     thread->tid = GetCurrentThreadId();
435baacf047SPaolo Bonzini }
436baacf047SPaolo Bonzini 
437baacf047SPaolo Bonzini HANDLE qemu_thread_get_handle(QemuThread *thread)
438baacf047SPaolo Bonzini {
439baacf047SPaolo Bonzini     QemuThreadData *data;
440baacf047SPaolo Bonzini     HANDLE handle;
441baacf047SPaolo Bonzini 
442baacf047SPaolo Bonzini     data = thread->data;
443ef57137fSPaolo Bonzini     if (data->mode == QEMU_THREAD_DETACHED) {
444baacf047SPaolo Bonzini         return NULL;
445baacf047SPaolo Bonzini     }
446baacf047SPaolo Bonzini 
447baacf047SPaolo Bonzini     EnterCriticalSection(&data->cs);
448baacf047SPaolo Bonzini     if (!data->exited) {
449b0cb0a66SVincent Palatin         handle = OpenThread(SYNCHRONIZE | THREAD_SUSPEND_RESUME |
450b0cb0a66SVincent Palatin                             THREAD_SET_CONTEXT, FALSE, thread->tid);
451baacf047SPaolo Bonzini     } else {
452baacf047SPaolo Bonzini         handle = NULL;
453baacf047SPaolo Bonzini     }
454baacf047SPaolo Bonzini     LeaveCriticalSection(&data->cs);
455baacf047SPaolo Bonzini     return handle;
456baacf047SPaolo Bonzini }
457baacf047SPaolo Bonzini 
458baacf047SPaolo Bonzini bool qemu_thread_is_self(QemuThread *thread)
459baacf047SPaolo Bonzini {
460baacf047SPaolo Bonzini     return GetCurrentThreadId() == thread->tid;
461baacf047SPaolo Bonzini }
462