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