1 /* 2 * Wrappers around mutex/cond/thread functions 3 * 4 * Copyright Red Hat, Inc. 2009 5 * 6 * Author: 7 * Marcelo Tosatti <mtosatti@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 #include "qemu/osdep.h" 14 #include "qemu/thread.h" 15 #include "qemu/atomic.h" 16 #include "qemu/notify.h" 17 #include "qemu-thread-common.h" 18 #include "qemu/tsan.h" 19 #include "qemu/bitmap.h" 20 21 #ifdef CONFIG_PTHREAD_SET_NAME_NP 22 #include <pthread_np.h> 23 #endif 24 25 static bool name_threads; 26 27 void qemu_thread_naming(bool enable) 28 { 29 name_threads = enable; 30 31 #if !defined CONFIG_PTHREAD_SETNAME_NP_W_TID && \ 32 !defined CONFIG_PTHREAD_SETNAME_NP_WO_TID && \ 33 !defined CONFIG_PTHREAD_SET_NAME_NP 34 /* This is a debugging option, not fatal */ 35 if (enable) { 36 fprintf(stderr, "qemu: thread naming not supported on this host\n"); 37 } 38 #endif 39 } 40 41 static void error_exit(int err, const char *msg) 42 { 43 fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err)); 44 abort(); 45 } 46 47 static inline clockid_t qemu_timedwait_clockid(void) 48 { 49 #ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK 50 return CLOCK_MONOTONIC; 51 #else 52 return CLOCK_REALTIME; 53 #endif 54 } 55 56 static void compute_abs_deadline(struct timespec *ts, int ms) 57 { 58 clock_gettime(qemu_timedwait_clockid(), ts); 59 ts->tv_nsec += (ms % 1000) * 1000000; 60 ts->tv_sec += ms / 1000; 61 if (ts->tv_nsec >= 1000000000) { 62 ts->tv_sec++; 63 ts->tv_nsec -= 1000000000; 64 } 65 } 66 67 void qemu_mutex_init(QemuMutex *mutex) 68 { 69 int err; 70 71 err = pthread_mutex_init(&mutex->lock, NULL); 72 if (err) 73 error_exit(err, __func__); 74 qemu_mutex_post_init(mutex); 75 } 76 77 void qemu_mutex_destroy(QemuMutex *mutex) 78 { 79 int err; 80 81 assert(mutex->initialized); 82 mutex->initialized = false; 83 err = pthread_mutex_destroy(&mutex->lock); 84 if (err) 85 error_exit(err, __func__); 86 } 87 88 void qemu_mutex_lock_impl(QemuMutex *mutex, const char *file, const int line) 89 { 90 int err; 91 92 assert(mutex->initialized); 93 qemu_mutex_pre_lock(mutex, file, line); 94 err = pthread_mutex_lock(&mutex->lock); 95 if (err) 96 error_exit(err, __func__); 97 qemu_mutex_post_lock(mutex, file, line); 98 } 99 100 int qemu_mutex_trylock_impl(QemuMutex *mutex, const char *file, const int line) 101 { 102 int err; 103 104 assert(mutex->initialized); 105 err = pthread_mutex_trylock(&mutex->lock); 106 if (err == 0) { 107 qemu_mutex_post_lock(mutex, file, line); 108 return 0; 109 } 110 if (err != EBUSY) { 111 error_exit(err, __func__); 112 } 113 return -EBUSY; 114 } 115 116 void qemu_mutex_unlock_impl(QemuMutex *mutex, const char *file, const int line) 117 { 118 int err; 119 120 assert(mutex->initialized); 121 qemu_mutex_pre_unlock(mutex, file, line); 122 err = pthread_mutex_unlock(&mutex->lock); 123 if (err) 124 error_exit(err, __func__); 125 } 126 127 void qemu_rec_mutex_init(QemuRecMutex *mutex) 128 { 129 int err; 130 pthread_mutexattr_t attr; 131 132 pthread_mutexattr_init(&attr); 133 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 134 err = pthread_mutex_init(&mutex->m.lock, &attr); 135 pthread_mutexattr_destroy(&attr); 136 if (err) { 137 error_exit(err, __func__); 138 } 139 mutex->m.initialized = true; 140 } 141 142 void qemu_rec_mutex_destroy(QemuRecMutex *mutex) 143 { 144 qemu_mutex_destroy(&mutex->m); 145 } 146 147 void qemu_rec_mutex_lock_impl(QemuRecMutex *mutex, const char *file, int line) 148 { 149 qemu_mutex_lock_impl(&mutex->m, file, line); 150 } 151 152 int qemu_rec_mutex_trylock_impl(QemuRecMutex *mutex, const char *file, int line) 153 { 154 return qemu_mutex_trylock_impl(&mutex->m, file, line); 155 } 156 157 void qemu_rec_mutex_unlock_impl(QemuRecMutex *mutex, const char *file, int line) 158 { 159 qemu_mutex_unlock_impl(&mutex->m, file, line); 160 } 161 162 void qemu_cond_init(QemuCond *cond) 163 { 164 pthread_condattr_t attr; 165 int err; 166 167 err = pthread_condattr_init(&attr); 168 if (err) { 169 error_exit(err, __func__); 170 } 171 #ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK 172 err = pthread_condattr_setclock(&attr, qemu_timedwait_clockid()); 173 if (err) { 174 error_exit(err, __func__); 175 } 176 #endif 177 err = pthread_cond_init(&cond->cond, &attr); 178 if (err) { 179 error_exit(err, __func__); 180 } 181 err = pthread_condattr_destroy(&attr); 182 if (err) { 183 error_exit(err, __func__); 184 } 185 cond->initialized = true; 186 } 187 188 void qemu_cond_destroy(QemuCond *cond) 189 { 190 int err; 191 192 assert(cond->initialized); 193 cond->initialized = false; 194 err = pthread_cond_destroy(&cond->cond); 195 if (err) 196 error_exit(err, __func__); 197 } 198 199 void qemu_cond_signal(QemuCond *cond) 200 { 201 int err; 202 203 assert(cond->initialized); 204 err = pthread_cond_signal(&cond->cond); 205 if (err) 206 error_exit(err, __func__); 207 } 208 209 void qemu_cond_broadcast(QemuCond *cond) 210 { 211 int err; 212 213 assert(cond->initialized); 214 err = pthread_cond_broadcast(&cond->cond); 215 if (err) 216 error_exit(err, __func__); 217 } 218 219 void qemu_cond_wait_impl(QemuCond *cond, QemuMutex *mutex, const char *file, const int line) 220 { 221 int err; 222 223 assert(cond->initialized); 224 qemu_mutex_pre_unlock(mutex, file, line); 225 err = pthread_cond_wait(&cond->cond, &mutex->lock); 226 qemu_mutex_post_lock(mutex, file, line); 227 if (err) 228 error_exit(err, __func__); 229 } 230 231 static bool TSA_NO_TSA 232 qemu_cond_timedwait_ts(QemuCond *cond, QemuMutex *mutex, struct timespec *ts, 233 const char *file, const int line) 234 { 235 int err; 236 237 assert(cond->initialized); 238 trace_qemu_mutex_unlock(mutex, file, line); 239 err = pthread_cond_timedwait(&cond->cond, &mutex->lock, ts); 240 trace_qemu_mutex_locked(mutex, file, line); 241 if (err && err != ETIMEDOUT) { 242 error_exit(err, __func__); 243 } 244 return err != ETIMEDOUT; 245 } 246 247 bool qemu_cond_timedwait_impl(QemuCond *cond, QemuMutex *mutex, int ms, 248 const char *file, const int line) 249 { 250 struct timespec ts; 251 252 compute_abs_deadline(&ts, ms); 253 return qemu_cond_timedwait_ts(cond, mutex, &ts, file, line); 254 } 255 256 void qemu_sem_init(QemuSemaphore *sem, int init) 257 { 258 qemu_mutex_init(&sem->mutex); 259 qemu_cond_init(&sem->cond); 260 261 if (init < 0) { 262 error_exit(EINVAL, __func__); 263 } 264 sem->count = init; 265 } 266 267 void qemu_sem_destroy(QemuSemaphore *sem) 268 { 269 qemu_cond_destroy(&sem->cond); 270 qemu_mutex_destroy(&sem->mutex); 271 } 272 273 void qemu_sem_post(QemuSemaphore *sem) 274 { 275 qemu_mutex_lock(&sem->mutex); 276 if (sem->count == UINT_MAX) { 277 error_exit(EINVAL, __func__); 278 } else { 279 sem->count++; 280 qemu_cond_signal(&sem->cond); 281 } 282 qemu_mutex_unlock(&sem->mutex); 283 } 284 285 int qemu_sem_timedwait(QemuSemaphore *sem, int ms) 286 { 287 bool rc = true; 288 struct timespec ts; 289 290 compute_abs_deadline(&ts, ms); 291 qemu_mutex_lock(&sem->mutex); 292 while (sem->count == 0) { 293 if (ms == 0) { 294 rc = false; 295 } else { 296 rc = qemu_cond_timedwait_ts(&sem->cond, &sem->mutex, &ts, 297 __FILE__, __LINE__); 298 } 299 if (!rc) { /* timeout */ 300 break; 301 } 302 } 303 if (rc) { 304 --sem->count; 305 } 306 qemu_mutex_unlock(&sem->mutex); 307 return (rc ? 0 : -1); 308 } 309 310 void qemu_sem_wait(QemuSemaphore *sem) 311 { 312 qemu_mutex_lock(&sem->mutex); 313 while (sem->count == 0) { 314 qemu_cond_wait(&sem->cond, &sem->mutex); 315 } 316 --sem->count; 317 qemu_mutex_unlock(&sem->mutex); 318 } 319 320 static __thread NotifierList thread_exit; 321 322 /* 323 * Note that in this implementation you can register a thread-exit 324 * notifier for the main thread, but it will never be called. 325 * This is OK because main thread exit can only happen when the 326 * entire process is exiting, and the API allows notifiers to not 327 * be called on process exit. 328 */ 329 void qemu_thread_atexit_add(Notifier *notifier) 330 { 331 notifier_list_add(&thread_exit, notifier); 332 } 333 334 void qemu_thread_atexit_remove(Notifier *notifier) 335 { 336 notifier_remove(notifier); 337 } 338 339 static void qemu_thread_atexit_notify(void *arg) 340 { 341 /* 342 * Called when non-main thread exits (via qemu_thread_exit() 343 * or by returning from its start routine.) 344 */ 345 notifier_list_notify(&thread_exit, NULL); 346 } 347 348 typedef struct { 349 void *(*start_routine)(void *); 350 void *arg; 351 char *name; 352 } QemuThreadArgs; 353 354 static void *qemu_thread_start(void *args) 355 { 356 QemuThreadArgs *qemu_thread_args = args; 357 void *(*start_routine)(void *) = qemu_thread_args->start_routine; 358 void *arg = qemu_thread_args->arg; 359 void *r; 360 361 /* Attempt to set the threads name; note that this is for debug, so 362 * we're not going to fail if we can't set it. 363 */ 364 if (name_threads && qemu_thread_args->name) { 365 # if defined(CONFIG_PTHREAD_SETNAME_NP_W_TID) 366 pthread_setname_np(pthread_self(), qemu_thread_args->name); 367 # elif defined(CONFIG_PTHREAD_SETNAME_NP_WO_TID) 368 pthread_setname_np(qemu_thread_args->name); 369 # elif defined(CONFIG_PTHREAD_SET_NAME_NP) 370 pthread_set_name_np(pthread_self(), qemu_thread_args->name); 371 # endif 372 } 373 QEMU_TSAN_ANNOTATE_THREAD_NAME(qemu_thread_args->name); 374 g_free(qemu_thread_args->name); 375 g_free(qemu_thread_args); 376 377 /* 378 * GCC 11 with glibc 2.17 on PowerPC reports 379 * 380 * qemu-thread-posix.c:540:5: error: ‘__sigsetjmp’ accessing 656 bytes 381 * in a region of size 528 [-Werror=stringop-overflow=] 382 * 540 | pthread_cleanup_push(qemu_thread_atexit_notify, NULL); 383 * | ^~~~~~~~~~~~~~~~~~~~ 384 * 385 * which is clearly nonsense. 386 */ 387 #pragma GCC diagnostic push 388 #ifndef __clang__ 389 #pragma GCC diagnostic ignored "-Wstringop-overflow" 390 #endif 391 392 pthread_cleanup_push(qemu_thread_atexit_notify, NULL); 393 r = start_routine(arg); 394 pthread_cleanup_pop(1); 395 396 #pragma GCC diagnostic pop 397 398 return r; 399 } 400 401 void qemu_thread_create(QemuThread *thread, const char *name, 402 void *(*start_routine)(void*), 403 void *arg, int mode) 404 { 405 sigset_t set, oldset; 406 int err; 407 pthread_attr_t attr; 408 QemuThreadArgs *qemu_thread_args; 409 410 err = pthread_attr_init(&attr); 411 if (err) { 412 error_exit(err, __func__); 413 } 414 415 if (mode == QEMU_THREAD_DETACHED) { 416 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 417 } 418 419 /* Leave signal handling to the iothread. */ 420 sigfillset(&set); 421 /* Blocking the signals can result in undefined behaviour. */ 422 sigdelset(&set, SIGSEGV); 423 sigdelset(&set, SIGFPE); 424 sigdelset(&set, SIGILL); 425 /* TODO avoid SIGBUS loss on macOS */ 426 pthread_sigmask(SIG_SETMASK, &set, &oldset); 427 428 qemu_thread_args = g_new0(QemuThreadArgs, 1); 429 qemu_thread_args->name = g_strdup(name); 430 qemu_thread_args->start_routine = start_routine; 431 qemu_thread_args->arg = arg; 432 433 err = pthread_create(&thread->thread, &attr, 434 qemu_thread_start, qemu_thread_args); 435 436 if (err) 437 error_exit(err, __func__); 438 439 pthread_sigmask(SIG_SETMASK, &oldset, NULL); 440 441 pthread_attr_destroy(&attr); 442 } 443 444 int qemu_thread_set_affinity(QemuThread *thread, unsigned long *host_cpus, 445 unsigned long nbits) 446 { 447 #if defined(CONFIG_PTHREAD_AFFINITY_NP) 448 const size_t setsize = CPU_ALLOC_SIZE(nbits); 449 unsigned long value; 450 cpu_set_t *cpuset; 451 int err; 452 453 cpuset = CPU_ALLOC(nbits); 454 g_assert(cpuset); 455 456 CPU_ZERO_S(setsize, cpuset); 457 value = find_first_bit(host_cpus, nbits); 458 while (value < nbits) { 459 CPU_SET_S(value, setsize, cpuset); 460 value = find_next_bit(host_cpus, nbits, value + 1); 461 } 462 463 err = pthread_setaffinity_np(thread->thread, setsize, cpuset); 464 CPU_FREE(cpuset); 465 return err; 466 #else 467 return -ENOSYS; 468 #endif 469 } 470 471 int qemu_thread_get_affinity(QemuThread *thread, unsigned long **host_cpus, 472 unsigned long *nbits) 473 { 474 #if defined(CONFIG_PTHREAD_AFFINITY_NP) 475 unsigned long tmpbits; 476 cpu_set_t *cpuset; 477 size_t setsize; 478 int i, err; 479 480 tmpbits = CPU_SETSIZE; 481 while (true) { 482 setsize = CPU_ALLOC_SIZE(tmpbits); 483 cpuset = CPU_ALLOC(tmpbits); 484 g_assert(cpuset); 485 486 err = pthread_getaffinity_np(thread->thread, setsize, cpuset); 487 if (err) { 488 CPU_FREE(cpuset); 489 if (err != -EINVAL) { 490 return err; 491 } 492 tmpbits *= 2; 493 } else { 494 break; 495 } 496 } 497 498 /* Convert the result into a proper bitmap. */ 499 *nbits = tmpbits; 500 *host_cpus = bitmap_new(tmpbits); 501 for (i = 0; i < tmpbits; i++) { 502 if (CPU_ISSET(i, cpuset)) { 503 set_bit(i, *host_cpus); 504 } 505 } 506 CPU_FREE(cpuset); 507 return 0; 508 #else 509 return -ENOSYS; 510 #endif 511 } 512 513 void qemu_thread_get_self(QemuThread *thread) 514 { 515 thread->thread = pthread_self(); 516 } 517 518 bool qemu_thread_is_self(QemuThread *thread) 519 { 520 return pthread_equal(pthread_self(), thread->thread); 521 } 522 523 void qemu_thread_exit(void *retval) 524 { 525 pthread_exit(retval); 526 } 527 528 void *qemu_thread_join(QemuThread *thread) 529 { 530 int err; 531 void *ret; 532 533 err = pthread_join(thread->thread, &ret); 534 if (err) { 535 error_exit(err, __func__); 536 } 537 return ret; 538 } 539