]> git.proxmox.com Git - mirror_qemu.git/blob - util/qemu-thread-win32.c
spapr: fix buffer-overflow
[mirror_qemu.git] / util / qemu-thread-win32.c
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 #ifndef _WIN32_WINNT
15 #define _WIN32_WINNT 0x0600
16 #endif
17
18 #include "qemu/osdep.h"
19 #include "qemu-common.h"
20 #include "qemu/thread.h"
21 #include "qemu/notify.h"
22 #include <process.h>
23
24 static bool name_threads;
25
26 void qemu_thread_naming(bool enable)
27 {
28 /* But note we don't actually name them on Windows yet */
29 name_threads = enable;
30
31 fprintf(stderr, "qemu: thread naming not supported on this host\n");
32 }
33
34 static void error_exit(int err, const char *msg)
35 {
36 char *pstr;
37
38 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
39 NULL, err, 0, (LPTSTR)&pstr, 2, NULL);
40 fprintf(stderr, "qemu: %s: %s\n", msg, pstr);
41 LocalFree(pstr);
42 abort();
43 }
44
45 void qemu_mutex_init(QemuMutex *mutex)
46 {
47 InitializeSRWLock(&mutex->lock);
48 }
49
50 void qemu_mutex_destroy(QemuMutex *mutex)
51 {
52 InitializeSRWLock(&mutex->lock);
53 }
54
55 void qemu_mutex_lock(QemuMutex *mutex)
56 {
57 AcquireSRWLockExclusive(&mutex->lock);
58 }
59
60 int qemu_mutex_trylock(QemuMutex *mutex)
61 {
62 int owned;
63
64 owned = TryAcquireSRWLockExclusive(&mutex->lock);
65 return !owned;
66 }
67
68 void qemu_mutex_unlock(QemuMutex *mutex)
69 {
70 ReleaseSRWLockExclusive(&mutex->lock);
71 }
72
73 void qemu_rec_mutex_init(QemuRecMutex *mutex)
74 {
75 InitializeCriticalSection(&mutex->lock);
76 }
77
78 void qemu_rec_mutex_destroy(QemuRecMutex *mutex)
79 {
80 DeleteCriticalSection(&mutex->lock);
81 }
82
83 void qemu_rec_mutex_lock(QemuRecMutex *mutex)
84 {
85 EnterCriticalSection(&mutex->lock);
86 }
87
88 int qemu_rec_mutex_trylock(QemuRecMutex *mutex)
89 {
90 return !TryEnterCriticalSection(&mutex->lock);
91 }
92
93 void qemu_rec_mutex_unlock(QemuRecMutex *mutex)
94 {
95 LeaveCriticalSection(&mutex->lock);
96 }
97
98 void qemu_cond_init(QemuCond *cond)
99 {
100 memset(cond, 0, sizeof(*cond));
101 InitializeConditionVariable(&cond->var);
102 }
103
104 void qemu_cond_destroy(QemuCond *cond)
105 {
106 InitializeConditionVariable(&cond->var);
107 }
108
109 void qemu_cond_signal(QemuCond *cond)
110 {
111 WakeConditionVariable(&cond->var);
112 }
113
114 void qemu_cond_broadcast(QemuCond *cond)
115 {
116 WakeAllConditionVariable(&cond->var);
117 }
118
119 void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
120 {
121 SleepConditionVariableSRW(&cond->var, &mutex->lock, INFINITE, 0);
122 }
123
124 void qemu_sem_init(QemuSemaphore *sem, int init)
125 {
126 /* Manual reset. */
127 sem->sema = CreateSemaphore(NULL, init, LONG_MAX, NULL);
128 }
129
130 void qemu_sem_destroy(QemuSemaphore *sem)
131 {
132 CloseHandle(sem->sema);
133 }
134
135 void qemu_sem_post(QemuSemaphore *sem)
136 {
137 ReleaseSemaphore(sem->sema, 1, NULL);
138 }
139
140 int qemu_sem_timedwait(QemuSemaphore *sem, int ms)
141 {
142 int rc = WaitForSingleObject(sem->sema, ms);
143 if (rc == WAIT_OBJECT_0) {
144 return 0;
145 }
146 if (rc != WAIT_TIMEOUT) {
147 error_exit(GetLastError(), __func__);
148 }
149 return -1;
150 }
151
152 void qemu_sem_wait(QemuSemaphore *sem)
153 {
154 if (WaitForSingleObject(sem->sema, INFINITE) != WAIT_OBJECT_0) {
155 error_exit(GetLastError(), __func__);
156 }
157 }
158
159 /* Wrap a Win32 manual-reset event with a fast userspace path. The idea
160 * is to reset the Win32 event lazily, as part of a test-reset-test-wait
161 * sequence. Such a sequence is, indeed, how QemuEvents are used by
162 * RCU and other subsystems!
163 *
164 * Valid transitions:
165 * - free->set, when setting the event
166 * - busy->set, when setting the event, followed by SetEvent
167 * - set->free, when resetting the event
168 * - free->busy, when waiting
169 *
170 * set->busy does not happen (it can be observed from the outside but
171 * it really is set->free->busy).
172 *
173 * busy->free provably cannot happen; to enforce it, the set->free transition
174 * is done with an OR, which becomes a no-op if the event has concurrently
175 * transitioned to free or busy (and is faster than cmpxchg).
176 */
177
178 #define EV_SET 0
179 #define EV_FREE 1
180 #define EV_BUSY -1
181
182 void qemu_event_init(QemuEvent *ev, bool init)
183 {
184 /* Manual reset. */
185 ev->event = CreateEvent(NULL, TRUE, TRUE, NULL);
186 ev->value = (init ? EV_SET : EV_FREE);
187 }
188
189 void qemu_event_destroy(QemuEvent *ev)
190 {
191 CloseHandle(ev->event);
192 }
193
194 void qemu_event_set(QemuEvent *ev)
195 {
196 /* qemu_event_set has release semantics, but because it *loads*
197 * ev->value we need a full memory barrier here.
198 */
199 smp_mb();
200 if (atomic_read(&ev->value) != EV_SET) {
201 if (atomic_xchg(&ev->value, EV_SET) == EV_BUSY) {
202 /* There were waiters, wake them up. */
203 SetEvent(ev->event);
204 }
205 }
206 }
207
208 void qemu_event_reset(QemuEvent *ev)
209 {
210 unsigned value;
211
212 value = atomic_read(&ev->value);
213 smp_mb_acquire();
214 if (value == EV_SET) {
215 /* If there was a concurrent reset (or even reset+wait),
216 * do nothing. Otherwise change EV_SET->EV_FREE.
217 */
218 atomic_or(&ev->value, EV_FREE);
219 }
220 }
221
222 void qemu_event_wait(QemuEvent *ev)
223 {
224 unsigned value;
225
226 value = atomic_read(&ev->value);
227 smp_mb_acquire();
228 if (value != EV_SET) {
229 if (value == EV_FREE) {
230 /* qemu_event_set is not yet going to call SetEvent, but we are
231 * going to do another check for EV_SET below when setting EV_BUSY.
232 * At that point it is safe to call WaitForSingleObject.
233 */
234 ResetEvent(ev->event);
235
236 /* Tell qemu_event_set that there are waiters. No need to retry
237 * because there cannot be a concurent busy->free transition.
238 * After the CAS, the event will be either set or busy.
239 */
240 if (atomic_cmpxchg(&ev->value, EV_FREE, EV_BUSY) == EV_SET) {
241 value = EV_SET;
242 } else {
243 value = EV_BUSY;
244 }
245 }
246 if (value == EV_BUSY) {
247 WaitForSingleObject(ev->event, INFINITE);
248 }
249 }
250 }
251
252 struct QemuThreadData {
253 /* Passed to win32_start_routine. */
254 void *(*start_routine)(void *);
255 void *arg;
256 short mode;
257 NotifierList exit;
258
259 /* Only used for joinable threads. */
260 bool exited;
261 void *ret;
262 CRITICAL_SECTION cs;
263 };
264
265 static bool atexit_registered;
266 static NotifierList main_thread_exit;
267
268 static __thread QemuThreadData *qemu_thread_data;
269
270 static void run_main_thread_exit(void)
271 {
272 notifier_list_notify(&main_thread_exit, NULL);
273 }
274
275 void qemu_thread_atexit_add(Notifier *notifier)
276 {
277 if (!qemu_thread_data) {
278 if (!atexit_registered) {
279 atexit_registered = true;
280 atexit(run_main_thread_exit);
281 }
282 notifier_list_add(&main_thread_exit, notifier);
283 } else {
284 notifier_list_add(&qemu_thread_data->exit, notifier);
285 }
286 }
287
288 void qemu_thread_atexit_remove(Notifier *notifier)
289 {
290 notifier_remove(notifier);
291 }
292
293 static unsigned __stdcall win32_start_routine(void *arg)
294 {
295 QemuThreadData *data = (QemuThreadData *) arg;
296 void *(*start_routine)(void *) = data->start_routine;
297 void *thread_arg = data->arg;
298
299 qemu_thread_data = data;
300 qemu_thread_exit(start_routine(thread_arg));
301 abort();
302 }
303
304 void qemu_thread_exit(void *arg)
305 {
306 QemuThreadData *data = qemu_thread_data;
307
308 notifier_list_notify(&data->exit, NULL);
309 if (data->mode == QEMU_THREAD_JOINABLE) {
310 data->ret = arg;
311 EnterCriticalSection(&data->cs);
312 data->exited = true;
313 LeaveCriticalSection(&data->cs);
314 } else {
315 g_free(data);
316 }
317 _endthreadex(0);
318 }
319
320 void *qemu_thread_join(QemuThread *thread)
321 {
322 QemuThreadData *data;
323 void *ret;
324 HANDLE handle;
325
326 data = thread->data;
327 if (data->mode == QEMU_THREAD_DETACHED) {
328 return NULL;
329 }
330
331 /*
332 * Because multiple copies of the QemuThread can exist via
333 * qemu_thread_get_self, we need to store a value that cannot
334 * leak there. The simplest, non racy way is to store the TID,
335 * discard the handle that _beginthreadex gives back, and
336 * get another copy of the handle here.
337 */
338 handle = qemu_thread_get_handle(thread);
339 if (handle) {
340 WaitForSingleObject(handle, INFINITE);
341 CloseHandle(handle);
342 }
343 ret = data->ret;
344 DeleteCriticalSection(&data->cs);
345 g_free(data);
346 return ret;
347 }
348
349 void qemu_thread_create(QemuThread *thread, const char *name,
350 void *(*start_routine)(void *),
351 void *arg, int mode)
352 {
353 HANDLE hThread;
354 struct QemuThreadData *data;
355
356 data = g_malloc(sizeof *data);
357 data->start_routine = start_routine;
358 data->arg = arg;
359 data->mode = mode;
360 data->exited = false;
361 notifier_list_init(&data->exit);
362
363 if (data->mode != QEMU_THREAD_DETACHED) {
364 InitializeCriticalSection(&data->cs);
365 }
366
367 hThread = (HANDLE) _beginthreadex(NULL, 0, win32_start_routine,
368 data, 0, &thread->tid);
369 if (!hThread) {
370 error_exit(GetLastError(), __func__);
371 }
372 CloseHandle(hThread);
373 thread->data = data;
374 }
375
376 void qemu_thread_get_self(QemuThread *thread)
377 {
378 thread->data = qemu_thread_data;
379 thread->tid = GetCurrentThreadId();
380 }
381
382 HANDLE qemu_thread_get_handle(QemuThread *thread)
383 {
384 QemuThreadData *data;
385 HANDLE handle;
386
387 data = thread->data;
388 if (data->mode == QEMU_THREAD_DETACHED) {
389 return NULL;
390 }
391
392 EnterCriticalSection(&data->cs);
393 if (!data->exited) {
394 handle = OpenThread(SYNCHRONIZE | THREAD_SUSPEND_RESUME |
395 THREAD_SET_CONTEXT, FALSE, thread->tid);
396 } else {
397 handle = NULL;
398 }
399 LeaveCriticalSection(&data->cs);
400 return handle;
401 }
402
403 bool qemu_thread_is_self(QemuThread *thread)
404 {
405 return GetCurrentThreadId() == thread->tid;
406 }