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