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