1
2
3
4
5
6
7
8
9
10
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
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
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
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
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
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
250
251
252 smp_mb();
253 if (qatomic_read(&ev->value) != EV_SET) {
254 if (qatomic_xchg(&ev->value, EV_SET) == EV_BUSY) {
255
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
270
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
286
287
288
289 ResetEvent(ev->event);
290
291
292
293
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
309 void *(*start_routine)(void *);
310 void *arg;
311 short mode;
312 NotifierList exit;
313
314
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
388
389
390
391
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}
462