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