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/thread.h" 16 #include "qemu/notify.h" 17 #include "qemu-thread-common.h" 18 #include <process.h> 19 20 static bool name_threads; 21 22 typedef HRESULT (WINAPI *pSetThreadDescription) (HANDLE hThread, 23 PCWSTR lpThreadDescription); 24 static pSetThreadDescription SetThreadDescriptionFunc; 25 static HMODULE kernel32_module; 26 27 static bool load_set_thread_description(void) 28 { 29 static gsize _init_once = 0; 30 31 if (g_once_init_enter(&_init_once)) { 32 kernel32_module = LoadLibrary("kernel32.dll"); 33 if (kernel32_module) { 34 SetThreadDescriptionFunc = 35 (pSetThreadDescription)GetProcAddress(kernel32_module, 36 "SetThreadDescription"); 37 if (!SetThreadDescriptionFunc) { 38 FreeLibrary(kernel32_module); 39 } 40 } 41 g_once_init_leave(&_init_once, 1); 42 } 43 44 return !!SetThreadDescriptionFunc; 45 } 46 47 void qemu_thread_naming(bool enable) 48 { 49 name_threads = enable; 50 51 if (enable && !load_set_thread_description()) { 52 fprintf(stderr, "qemu: thread naming not supported on this host\n"); 53 name_threads = false; 54 } 55 } 56 57 static void error_exit(int err, const char *msg) 58 { 59 char *pstr; 60 61 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, 62 NULL, err, 0, (LPTSTR)&pstr, 2, NULL); 63 fprintf(stderr, "qemu: %s: %s\n", msg, pstr); 64 LocalFree(pstr); 65 abort(); 66 } 67 68 void qemu_mutex_init(QemuMutex *mutex) 69 { 70 InitializeSRWLock(&mutex->lock); 71 qemu_mutex_post_init(mutex); 72 } 73 74 void qemu_mutex_destroy(QemuMutex *mutex) 75 { 76 assert(mutex->initialized); 77 mutex->initialized = false; 78 InitializeSRWLock(&mutex->lock); 79 } 80 81 void qemu_mutex_lock_impl(QemuMutex *mutex, const char *file, const int line) 82 { 83 assert(mutex->initialized); 84 qemu_mutex_pre_lock(mutex, file, line); 85 AcquireSRWLockExclusive(&mutex->lock); 86 qemu_mutex_post_lock(mutex, file, line); 87 } 88 89 int qemu_mutex_trylock_impl(QemuMutex *mutex, const char *file, const int line) 90 { 91 int owned; 92 93 assert(mutex->initialized); 94 owned = TryAcquireSRWLockExclusive(&mutex->lock); 95 if (owned) { 96 qemu_mutex_post_lock(mutex, file, line); 97 return 0; 98 } 99 return -EBUSY; 100 } 101 102 void qemu_mutex_unlock_impl(QemuMutex *mutex, const char *file, const int line) 103 { 104 assert(mutex->initialized); 105 qemu_mutex_pre_unlock(mutex, file, line); 106 ReleaseSRWLockExclusive(&mutex->lock); 107 } 108 109 void qemu_rec_mutex_init(QemuRecMutex *mutex) 110 { 111 InitializeCriticalSection(&mutex->lock); 112 mutex->initialized = true; 113 } 114 115 void qemu_rec_mutex_destroy(QemuRecMutex *mutex) 116 { 117 assert(mutex->initialized); 118 mutex->initialized = false; 119 DeleteCriticalSection(&mutex->lock); 120 } 121 122 void qemu_rec_mutex_lock_impl(QemuRecMutex *mutex, const char *file, int line) 123 { 124 assert(mutex->initialized); 125 EnterCriticalSection(&mutex->lock); 126 } 127 128 int qemu_rec_mutex_trylock_impl(QemuRecMutex *mutex, const char *file, int line) 129 { 130 assert(mutex->initialized); 131 return !TryEnterCriticalSection(&mutex->lock); 132 } 133 134 void qemu_rec_mutex_unlock_impl(QemuRecMutex *mutex, const char *file, int line) 135 { 136 assert(mutex->initialized); 137 LeaveCriticalSection(&mutex->lock); 138 } 139 140 void qemu_cond_init(QemuCond *cond) 141 { 142 memset(cond, 0, sizeof(*cond)); 143 InitializeConditionVariable(&cond->var); 144 cond->initialized = true; 145 } 146 147 void qemu_cond_destroy(QemuCond *cond) 148 { 149 assert(cond->initialized); 150 cond->initialized = false; 151 InitializeConditionVariable(&cond->var); 152 } 153 154 void qemu_cond_signal(QemuCond *cond) 155 { 156 assert(cond->initialized); 157 WakeConditionVariable(&cond->var); 158 } 159 160 void qemu_cond_broadcast(QemuCond *cond) 161 { 162 assert(cond->initialized); 163 WakeAllConditionVariable(&cond->var); 164 } 165 166 void qemu_cond_wait_impl(QemuCond *cond, QemuMutex *mutex, const char *file, const int line) 167 { 168 assert(cond->initialized); 169 qemu_mutex_pre_unlock(mutex, file, line); 170 SleepConditionVariableSRW(&cond->var, &mutex->lock, INFINITE, 0); 171 qemu_mutex_post_lock(mutex, file, line); 172 } 173 174 bool qemu_cond_timedwait_impl(QemuCond *cond, QemuMutex *mutex, int ms, 175 const char *file, const int line) 176 { 177 int rc = 0; 178 179 assert(cond->initialized); 180 trace_qemu_mutex_unlock(mutex, file, line); 181 if (!SleepConditionVariableSRW(&cond->var, &mutex->lock, ms, 0)) { 182 rc = GetLastError(); 183 } 184 trace_qemu_mutex_locked(mutex, file, line); 185 if (rc && rc != ERROR_TIMEOUT) { 186 error_exit(rc, __func__); 187 } 188 return rc != ERROR_TIMEOUT; 189 } 190 191 void qemu_sem_init(QemuSemaphore *sem, int init) 192 { 193 /* Manual reset. */ 194 sem->sema = CreateSemaphore(NULL, init, LONG_MAX, NULL); 195 sem->initialized = true; 196 } 197 198 void qemu_sem_destroy(QemuSemaphore *sem) 199 { 200 assert(sem->initialized); 201 sem->initialized = false; 202 CloseHandle(sem->sema); 203 } 204 205 void qemu_sem_post(QemuSemaphore *sem) 206 { 207 assert(sem->initialized); 208 ReleaseSemaphore(sem->sema, 1, NULL); 209 } 210 211 int qemu_sem_timedwait(QemuSemaphore *sem, int ms) 212 { 213 int rc; 214 215 assert(sem->initialized); 216 rc = WaitForSingleObject(sem->sema, ms); 217 if (rc == WAIT_OBJECT_0) { 218 return 0; 219 } 220 if (rc != WAIT_TIMEOUT) { 221 error_exit(GetLastError(), __func__); 222 } 223 return -1; 224 } 225 226 void qemu_sem_wait(QemuSemaphore *sem) 227 { 228 assert(sem->initialized); 229 if (WaitForSingleObject(sem->sema, INFINITE) != WAIT_OBJECT_0) { 230 error_exit(GetLastError(), __func__); 231 } 232 } 233 234 /* Wrap a Win32 manual-reset event with a fast userspace path. The idea 235 * is to reset the Win32 event lazily, as part of a test-reset-test-wait 236 * sequence. Such a sequence is, indeed, how QemuEvents are used by 237 * RCU and other subsystems! 238 * 239 * Valid transitions: 240 * - free->set, when setting the event 241 * - busy->set, when setting the event, followed by SetEvent 242 * - set->free, when resetting the event 243 * - free->busy, when waiting 244 * 245 * set->busy does not happen (it can be observed from the outside but 246 * it really is set->free->busy). 247 * 248 * busy->free provably cannot happen; to enforce it, the set->free transition 249 * is done with an OR, which becomes a no-op if the event has concurrently 250 * transitioned to free or busy (and is faster than cmpxchg). 251 */ 252 253 #define EV_SET 0 254 #define EV_FREE 1 255 #define EV_BUSY -1 256 257 void qemu_event_init(QemuEvent *ev, bool init) 258 { 259 /* Manual reset. */ 260 ev->event = CreateEvent(NULL, TRUE, TRUE, NULL); 261 ev->value = (init ? EV_SET : EV_FREE); 262 ev->initialized = true; 263 } 264 265 void qemu_event_destroy(QemuEvent *ev) 266 { 267 assert(ev->initialized); 268 ev->initialized = false; 269 CloseHandle(ev->event); 270 } 271 272 void qemu_event_set(QemuEvent *ev) 273 { 274 assert(ev->initialized); 275 /* qemu_event_set has release semantics, but because it *loads* 276 * ev->value we need a full memory barrier here. 277 */ 278 smp_mb(); 279 if (qatomic_read(&ev->value) != EV_SET) { 280 if (qatomic_xchg(&ev->value, EV_SET) == EV_BUSY) { 281 /* There were waiters, wake them up. */ 282 SetEvent(ev->event); 283 } 284 } 285 } 286 287 void qemu_event_reset(QemuEvent *ev) 288 { 289 unsigned value; 290 291 assert(ev->initialized); 292 value = qatomic_read(&ev->value); 293 smp_mb_acquire(); 294 if (value == EV_SET) { 295 /* If there was a concurrent reset (or even reset+wait), 296 * do nothing. Otherwise change EV_SET->EV_FREE. 297 */ 298 qatomic_or(&ev->value, EV_FREE); 299 } 300 } 301 302 void qemu_event_wait(QemuEvent *ev) 303 { 304 unsigned value; 305 306 assert(ev->initialized); 307 value = qatomic_read(&ev->value); 308 smp_mb_acquire(); 309 if (value != EV_SET) { 310 if (value == EV_FREE) { 311 /* qemu_event_set is not yet going to call SetEvent, but we are 312 * going to do another check for EV_SET below when setting EV_BUSY. 313 * At that point it is safe to call WaitForSingleObject. 314 */ 315 ResetEvent(ev->event); 316 317 /* Tell qemu_event_set that there are waiters. No need to retry 318 * because there cannot be a concurrent busy->free transition. 319 * After the CAS, the event will be either set or busy. 320 */ 321 if (qatomic_cmpxchg(&ev->value, EV_FREE, EV_BUSY) == EV_SET) { 322 value = EV_SET; 323 } else { 324 value = EV_BUSY; 325 } 326 } 327 if (value == EV_BUSY) { 328 WaitForSingleObject(ev->event, INFINITE); 329 } 330 } 331 } 332 333 struct QemuThreadData { 334 /* Passed to win32_start_routine. */ 335 void *(*start_routine)(void *); 336 void *arg; 337 short mode; 338 NotifierList exit; 339 340 /* Only used for joinable threads. */ 341 bool exited; 342 void *ret; 343 CRITICAL_SECTION cs; 344 }; 345 346 static bool atexit_registered; 347 static NotifierList main_thread_exit; 348 349 static __thread QemuThreadData *qemu_thread_data; 350 351 static void run_main_thread_exit(void) 352 { 353 notifier_list_notify(&main_thread_exit, NULL); 354 } 355 356 void qemu_thread_atexit_add(Notifier *notifier) 357 { 358 if (!qemu_thread_data) { 359 if (!atexit_registered) { 360 atexit_registered = true; 361 atexit(run_main_thread_exit); 362 } 363 notifier_list_add(&main_thread_exit, notifier); 364 } else { 365 notifier_list_add(&qemu_thread_data->exit, notifier); 366 } 367 } 368 369 void qemu_thread_atexit_remove(Notifier *notifier) 370 { 371 notifier_remove(notifier); 372 } 373 374 static unsigned __stdcall win32_start_routine(void *arg) 375 { 376 QemuThreadData *data = (QemuThreadData *) arg; 377 void *(*start_routine)(void *) = data->start_routine; 378 void *thread_arg = data->arg; 379 380 qemu_thread_data = data; 381 qemu_thread_exit(start_routine(thread_arg)); 382 abort(); 383 } 384 385 void qemu_thread_exit(void *arg) 386 { 387 QemuThreadData *data = qemu_thread_data; 388 389 notifier_list_notify(&data->exit, NULL); 390 if (data->mode == QEMU_THREAD_JOINABLE) { 391 data->ret = arg; 392 EnterCriticalSection(&data->cs); 393 data->exited = true; 394 LeaveCriticalSection(&data->cs); 395 } else { 396 g_free(data); 397 } 398 _endthreadex(0); 399 } 400 401 void *qemu_thread_join(QemuThread *thread) 402 { 403 QemuThreadData *data; 404 void *ret; 405 HANDLE handle; 406 407 data = thread->data; 408 if (data->mode == QEMU_THREAD_DETACHED) { 409 return NULL; 410 } 411 412 /* 413 * Because multiple copies of the QemuThread can exist via 414 * qemu_thread_get_self, we need to store a value that cannot 415 * leak there. The simplest, non racy way is to store the TID, 416 * discard the handle that _beginthreadex gives back, and 417 * get another copy of the handle here. 418 */ 419 handle = qemu_thread_get_handle(thread); 420 if (handle) { 421 WaitForSingleObject(handle, INFINITE); 422 CloseHandle(handle); 423 } 424 ret = data->ret; 425 DeleteCriticalSection(&data->cs); 426 g_free(data); 427 return ret; 428 } 429 430 static bool set_thread_description(HANDLE h, const char *name) 431 { 432 HRESULT hr; 433 g_autofree wchar_t *namew = NULL; 434 435 if (!load_set_thread_description()) { 436 return false; 437 } 438 439 namew = g_utf8_to_utf16(name, -1, NULL, NULL, NULL); 440 if (!namew) { 441 return false; 442 } 443 444 hr = SetThreadDescriptionFunc(h, namew); 445 446 return SUCCEEDED(hr); 447 } 448 449 void qemu_thread_create(QemuThread *thread, const char *name, 450 void *(*start_routine)(void *), 451 void *arg, int mode) 452 { 453 HANDLE hThread; 454 struct QemuThreadData *data; 455 456 data = g_malloc(sizeof *data); 457 data->start_routine = start_routine; 458 data->arg = arg; 459 data->mode = mode; 460 data->exited = false; 461 notifier_list_init(&data->exit); 462 463 if (data->mode != QEMU_THREAD_DETACHED) { 464 InitializeCriticalSection(&data->cs); 465 } 466 467 hThread = (HANDLE) _beginthreadex(NULL, 0, win32_start_routine, 468 data, 0, &thread->tid); 469 if (!hThread) { 470 error_exit(GetLastError(), __func__); 471 } 472 if (name_threads && name && !set_thread_description(hThread, name)) { 473 fprintf(stderr, "qemu: failed to set thread description: %s\n", name); 474 } 475 CloseHandle(hThread); 476 477 thread->data = data; 478 } 479 480 void qemu_thread_get_self(QemuThread *thread) 481 { 482 thread->data = qemu_thread_data; 483 thread->tid = GetCurrentThreadId(); 484 } 485 486 HANDLE qemu_thread_get_handle(QemuThread *thread) 487 { 488 QemuThreadData *data; 489 HANDLE handle; 490 491 data = thread->data; 492 if (data->mode == QEMU_THREAD_DETACHED) { 493 return NULL; 494 } 495 496 EnterCriticalSection(&data->cs); 497 if (!data->exited) { 498 handle = OpenThread(SYNCHRONIZE | THREAD_SUSPEND_RESUME | 499 THREAD_SET_CONTEXT, FALSE, thread->tid); 500 } else { 501 handle = NULL; 502 } 503 LeaveCriticalSection(&data->cs); 504 return handle; 505 } 506 507 bool qemu_thread_is_self(QemuThread *thread) 508 { 509 return GetCurrentThreadId() == thread->tid; 510 } 511