qemu-thread-win32.c (11830B)
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-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 /* But note we don't actually name them on Windows yet */ 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 /* Manual reset. */ 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/* Wrap a Win32 manual-reset event with a fast userspace path. The idea 209 * is to reset the Win32 event lazily, as part of a test-reset-test-wait 210 * sequence. Such a sequence is, indeed, how QemuEvents are used by 211 * RCU and other subsystems! 212 * 213 * Valid transitions: 214 * - free->set, when setting the event 215 * - busy->set, when setting the event, followed by SetEvent 216 * - set->free, when resetting the event 217 * - free->busy, when waiting 218 * 219 * set->busy does not happen (it can be observed from the outside but 220 * it really is set->free->busy). 221 * 222 * busy->free provably cannot happen; to enforce it, the set->free transition 223 * is done with an OR, which becomes a no-op if the event has concurrently 224 * transitioned to free or busy (and is faster than cmpxchg). 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 /* Manual reset. */ 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 /* qemu_event_set has release semantics, but because it *loads* 250 * ev->value we need a full memory barrier here. 251 */ 252 smp_mb(); 253 if (qatomic_read(&ev->value) != EV_SET) { 254 if (qatomic_xchg(&ev->value, EV_SET) == EV_BUSY) { 255 /* There were waiters, wake them up. */ 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 /* If there was a concurrent reset (or even reset+wait), 270 * do nothing. Otherwise change EV_SET->EV_FREE. 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 /* qemu_event_set is not yet going to call SetEvent, but we are 286 * going to do another check for EV_SET below when setting EV_BUSY. 287 * At that point it is safe to call WaitForSingleObject. 288 */ 289 ResetEvent(ev->event); 290 291 /* Tell qemu_event_set that there are waiters. No need to retry 292 * because there cannot be a concurrent busy->free transition. 293 * After the CAS, the event will be either set or busy. 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 /* Passed to win32_start_routine. */ 309 void *(*start_routine)(void *); 310 void *arg; 311 short mode; 312 NotifierList exit; 313 314 /* Only used for joinable threads. */ 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 * Because multiple copies of the QemuThread can exist via 388 * qemu_thread_get_self, we need to store a value that cannot 389 * leak there. The simplest, non racy way is to store the TID, 390 * discard the handle that _beginthreadex gives back, and 391 * get another copy of the handle here. 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}