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