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