* See the COPYING file in the top-level directory.
*
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <time.h>
-#include <signal.h>
-#include <stdint.h>
-#include <string.h>
-#include <limits.h>
-#include <unistd.h>
-#include <sys/time.h>
-#ifdef __linux__
-#include <sys/syscall.h>
-#include <linux/futex.h>
-#endif
+#include "qemu/osdep.h"
#include "qemu/thread.h"
#include "qemu/atomic.h"
#include "qemu/notify.h"
+#include "trace.h"
static bool name_threads;
void qemu_mutex_init(QemuMutex *mutex)
{
int err;
- pthread_mutexattr_t mutexattr;
- pthread_mutexattr_init(&mutexattr);
- pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_ERRORCHECK);
- err = pthread_mutex_init(&mutex->lock, &mutexattr);
- pthread_mutexattr_destroy(&mutexattr);
+ err = pthread_mutex_init(&mutex->lock, NULL);
if (err)
error_exit(err, __func__);
+ mutex->initialized = true;
}
void qemu_mutex_destroy(QemuMutex *mutex)
{
int err;
+ assert(mutex->initialized);
+ mutex->initialized = false;
err = pthread_mutex_destroy(&mutex->lock);
if (err)
error_exit(err, __func__);
}
-void qemu_mutex_lock(QemuMutex *mutex)
+void qemu_mutex_lock_impl(QemuMutex *mutex, const char *file, const int line)
{
int err;
+ assert(mutex->initialized);
+ trace_qemu_mutex_lock(mutex, file, line);
+
err = pthread_mutex_lock(&mutex->lock);
if (err)
error_exit(err, __func__);
+
+ trace_qemu_mutex_locked(mutex, file, line);
}
-int qemu_mutex_trylock(QemuMutex *mutex)
+int qemu_mutex_trylock_impl(QemuMutex *mutex, const char *file, const int line)
{
- return pthread_mutex_trylock(&mutex->lock);
+ int err;
+
+ assert(mutex->initialized);
+ err = pthread_mutex_trylock(&mutex->lock);
+ if (err == 0) {
+ trace_qemu_mutex_locked(mutex, file, line);
+ return 0;
+ }
+ if (err != EBUSY) {
+ error_exit(err, __func__);
+ }
+ return -EBUSY;
}
-void qemu_mutex_unlock(QemuMutex *mutex)
+void qemu_mutex_unlock_impl(QemuMutex *mutex, const char *file, const int line)
{
int err;
+ assert(mutex->initialized);
err = pthread_mutex_unlock(&mutex->lock);
if (err)
error_exit(err, __func__);
+
+ trace_qemu_mutex_unlock(mutex, file, line);
+}
+
+void qemu_rec_mutex_init(QemuRecMutex *mutex)
+{
+ int err;
+ pthread_mutexattr_t attr;
+
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ err = pthread_mutex_init(&mutex->lock, &attr);
+ pthread_mutexattr_destroy(&attr);
+ if (err) {
+ error_exit(err, __func__);
+ }
+ mutex->initialized = true;
}
void qemu_cond_init(QemuCond *cond)
err = pthread_cond_init(&cond->cond, NULL);
if (err)
error_exit(err, __func__);
+ cond->initialized = true;
}
void qemu_cond_destroy(QemuCond *cond)
{
int err;
+ assert(cond->initialized);
+ cond->initialized = false;
err = pthread_cond_destroy(&cond->cond);
if (err)
error_exit(err, __func__);
{
int err;
+ assert(cond->initialized);
err = pthread_cond_signal(&cond->cond);
if (err)
error_exit(err, __func__);
{
int err;
+ assert(cond->initialized);
err = pthread_cond_broadcast(&cond->cond);
if (err)
error_exit(err, __func__);
}
-void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
+void qemu_cond_wait_impl(QemuCond *cond, QemuMutex *mutex, const char *file, const int line)
{
int err;
+ assert(cond->initialized);
+ trace_qemu_mutex_unlock(mutex, file, line);
err = pthread_cond_wait(&cond->cond, &mutex->lock);
+ trace_qemu_mutex_locked(mutex, file, line);
if (err)
error_exit(err, __func__);
}
{
int rc;
-#if defined(__APPLE__) || defined(__NetBSD__)
+#ifndef CONFIG_SEM_TIMEDWAIT
rc = pthread_mutex_init(&sem->lock, NULL);
if (rc != 0) {
error_exit(rc, __func__);
error_exit(errno, __func__);
}
#endif
+ sem->initialized = true;
}
void qemu_sem_destroy(QemuSemaphore *sem)
{
int rc;
-#if defined(__APPLE__) || defined(__NetBSD__)
+ assert(sem->initialized);
+ sem->initialized = false;
+#ifndef CONFIG_SEM_TIMEDWAIT
rc = pthread_cond_destroy(&sem->cond);
if (rc < 0) {
error_exit(rc, __func__);
{
int rc;
-#if defined(__APPLE__) || defined(__NetBSD__)
+ assert(sem->initialized);
+#ifndef CONFIG_SEM_TIMEDWAIT
pthread_mutex_lock(&sem->lock);
if (sem->count == UINT_MAX) {
rc = EINVAL;
int rc;
struct timespec ts;
-#if defined(__APPLE__) || defined(__NetBSD__)
+ assert(sem->initialized);
+#ifndef CONFIG_SEM_TIMEDWAIT
rc = 0;
compute_abs_deadline(&ts, ms);
pthread_mutex_lock(&sem->lock);
{
int rc;
-#if defined(__APPLE__) || defined(__NetBSD__)
+ assert(sem->initialized);
+#ifndef CONFIG_SEM_TIMEDWAIT
pthread_mutex_lock(&sem->lock);
while (sem->count == 0) {
rc = pthread_cond_wait(&sem->cond, &sem->lock);
}
#ifdef __linux__
-#define futex(...) syscall(__NR_futex, __VA_ARGS__)
-
-static inline void futex_wake(QemuEvent *ev, int n)
-{
- futex(ev, FUTEX_WAKE, n, NULL, NULL, 0);
-}
-
-static inline void futex_wait(QemuEvent *ev, unsigned val)
-{
- futex(ev, FUTEX_WAIT, (int) val, NULL, NULL, 0);
-}
+#include "qemu/futex.h"
#else
-static inline void futex_wake(QemuEvent *ev, int n)
+static inline void qemu_futex_wake(QemuEvent *ev, int n)
{
+ assert(ev->initialized);
pthread_mutex_lock(&ev->lock);
if (n == 1) {
pthread_cond_signal(&ev->cond);
pthread_mutex_unlock(&ev->lock);
}
-static inline void futex_wait(QemuEvent *ev, unsigned val)
+static inline void qemu_futex_wait(QemuEvent *ev, unsigned val)
{
+ assert(ev->initialized);
pthread_mutex_lock(&ev->lock);
if (ev->value == val) {
pthread_cond_wait(&ev->cond, &ev->lock);
/* Valid transitions:
* - free->set, when setting the event
- * - busy->set, when setting the event, followed by futex_wake
+ * - busy->set, when setting the event, followed by qemu_futex_wake
* - set->free, when resetting the event
* - free->busy, when waiting
*
#endif
ev->value = (init ? EV_SET : EV_FREE);
+ ev->initialized = true;
}
void qemu_event_destroy(QemuEvent *ev)
{
+ assert(ev->initialized);
+ ev->initialized = false;
#ifndef __linux__
pthread_mutex_destroy(&ev->lock);
pthread_cond_destroy(&ev->cond);
void qemu_event_set(QemuEvent *ev)
{
- if (atomic_mb_read(&ev->value) != EV_SET) {
+ /* qemu_event_set has release semantics, but because it *loads*
+ * ev->value we need a full memory barrier here.
+ */
+ assert(ev->initialized);
+ smp_mb();
+ if (atomic_read(&ev->value) != EV_SET) {
if (atomic_xchg(&ev->value, EV_SET) == EV_BUSY) {
/* There were waiters, wake them up. */
- futex_wake(ev, INT_MAX);
+ qemu_futex_wake(ev, INT_MAX);
}
}
}
void qemu_event_reset(QemuEvent *ev)
{
- if (atomic_mb_read(&ev->value) == EV_SET) {
+ unsigned value;
+
+ assert(ev->initialized);
+ value = atomic_read(&ev->value);
+ smp_mb_acquire();
+ if (value == EV_SET) {
/*
* If there was a concurrent reset (or even reset+wait),
* do nothing. Otherwise change EV_SET->EV_FREE.
{
unsigned value;
- value = atomic_mb_read(&ev->value);
+ assert(ev->initialized);
+ value = atomic_read(&ev->value);
+ smp_mb_acquire();
if (value != EV_SET) {
if (value == EV_FREE) {
/*
* Leave the event reset and tell qemu_event_set that there
* are waiters. No need to retry, because there cannot be
- * a concurent busy->free transition. After the CAS, the
+ * a concurrent busy->free transition. After the CAS, the
* event will be either set or busy.
*/
if (atomic_cmpxchg(&ev->value, EV_FREE, EV_BUSY) == EV_SET) {
return;
}
}
- futex_wait(ev, EV_BUSY);
+ qemu_futex_wait(ev, EV_BUSY);
}
}
}
-/* Attempt to set the threads name; note that this is for debug, so
- * we're not going to fail if we can't set it.
- */
-static void qemu_thread_set_name(QemuThread *thread, const char *name)
-{
#ifdef CONFIG_PTHREAD_SETNAME_NP
- pthread_setname_np(thread->thread, name);
-#endif
+typedef struct {
+ void *(*start_routine)(void *);
+ void *arg;
+ char *name;
+} QemuThreadArgs;
+
+static void *qemu_thread_start(void *args)
+{
+ QemuThreadArgs *qemu_thread_args = args;
+ void *(*start_routine)(void *) = qemu_thread_args->start_routine;
+ void *arg = qemu_thread_args->arg;
+
+ /* Attempt to set the threads name; note that this is for debug, so
+ * we're not going to fail if we can't set it.
+ */
+ pthread_setname_np(pthread_self(), qemu_thread_args->name);
+ g_free(qemu_thread_args->name);
+ g_free(qemu_thread_args);
+ return start_routine(arg);
}
+#endif
+
void qemu_thread_create(QemuThread *thread, const char *name,
void *(*start_routine)(void*),
if (err) {
error_exit(err, __func__);
}
+
if (mode == QEMU_THREAD_DETACHED) {
- err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- if (err) {
- error_exit(err, __func__);
- }
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
}
/* Leave signal handling to the iothread. */
sigfillset(&set);
pthread_sigmask(SIG_SETMASK, &set, &oldset);
- err = pthread_create(&thread->thread, &attr, start_routine, arg);
- if (err)
- error_exit(err, __func__);
+#ifdef CONFIG_PTHREAD_SETNAME_NP
if (name_threads) {
- qemu_thread_set_name(thread, name);
+ QemuThreadArgs *qemu_thread_args;
+ qemu_thread_args = g_new0(QemuThreadArgs, 1);
+ qemu_thread_args->name = g_strdup(name);
+ qemu_thread_args->start_routine = start_routine;
+ qemu_thread_args->arg = arg;
+
+ err = pthread_create(&thread->thread, &attr,
+ qemu_thread_start, qemu_thread_args);
+ } else
+#endif
+ {
+ err = pthread_create(&thread->thread, &attr,
+ start_routine, arg);
}
+ if (err)
+ error_exit(err, __func__);
+
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
pthread_attr_destroy(&attr);