X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=qemu-thread-posix.c;h=4ef9c7b3f83469c87d09b66751ceb2e67e7877e1;hb=16c915ba42b45df7a64a6908287f03bfa3764bed;hp=8b54cc0262d4d7e8c04f2bb4b33c2ad6f9cc8204;hpb=89b48b56812a1a2d5b7edc927a7853d952e7fb38;p=qemu.git diff --git a/qemu-thread-posix.c b/qemu-thread-posix.c index 8b54cc026..4ef9c7b3f 100644 --- a/qemu-thread-posix.c +++ b/qemu-thread-posix.c @@ -17,12 +17,15 @@ #include #include #include +#include +#include +#include #include "qemu-thread.h" static void error_exit(int err, const char *msg) { fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err)); - exit(1); + abort(); } void qemu_mutex_init(QemuMutex *mutex) @@ -61,30 +64,6 @@ int qemu_mutex_trylock(QemuMutex *mutex) return pthread_mutex_trylock(&mutex->lock); } -static void timespec_add_ms(struct timespec *ts, uint64_t msecs) -{ - ts->tv_sec = ts->tv_sec + (long)(msecs / 1000); - ts->tv_nsec = (ts->tv_nsec + ((long)msecs % 1000) * 1000000); - if (ts->tv_nsec >= 1000000000) { - ts->tv_nsec -= 1000000000; - ts->tv_sec++; - } -} - -int qemu_mutex_timedlock(QemuMutex *mutex, uint64_t msecs) -{ - int err; - struct timespec ts; - - clock_gettime(CLOCK_REALTIME, &ts); - timespec_add_ms(&ts, msecs); - - err = pthread_mutex_timedlock(&mutex->lock, &ts); - if (err && err != ETIMEDOUT) - error_exit(err, __func__); - return err; -} - void qemu_mutex_unlock(QemuMutex *mutex) { int err; @@ -139,45 +118,184 @@ void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex) error_exit(err, __func__); } -int qemu_cond_timedwait(QemuCond *cond, QemuMutex *mutex, uint64_t msecs) +void qemu_sem_init(QemuSemaphore *sem, int init) +{ + int rc; + +#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__) + rc = pthread_mutex_init(&sem->lock, NULL); + if (rc != 0) { + error_exit(rc, __func__); + } + rc = pthread_cond_init(&sem->cond, NULL); + if (rc != 0) { + error_exit(rc, __func__); + } + if (init < 0) { + error_exit(EINVAL, __func__); + } + sem->count = init; +#else + rc = sem_init(&sem->sem, 0, init); + if (rc < 0) { + error_exit(errno, __func__); + } +#endif +} + +void qemu_sem_destroy(QemuSemaphore *sem) +{ + int rc; + +#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__) + rc = pthread_cond_destroy(&sem->cond); + if (rc < 0) { + error_exit(rc, __func__); + } + rc = pthread_mutex_destroy(&sem->lock); + if (rc < 0) { + error_exit(rc, __func__); + } +#else + rc = sem_destroy(&sem->sem); + if (rc < 0) { + error_exit(errno, __func__); + } +#endif +} + +void qemu_sem_post(QemuSemaphore *sem) +{ + int rc; + +#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__) + pthread_mutex_lock(&sem->lock); + if (sem->count == INT_MAX) { + rc = EINVAL; + } else if (sem->count++ < 0) { + rc = pthread_cond_signal(&sem->cond); + } else { + rc = 0; + } + pthread_mutex_unlock(&sem->lock); + if (rc != 0) { + error_exit(rc, __func__); + } +#else + rc = sem_post(&sem->sem); + if (rc < 0) { + error_exit(errno, __func__); + } +#endif +} + +static void compute_abs_deadline(struct timespec *ts, int ms) { + struct timeval tv; + gettimeofday(&tv, NULL); + ts->tv_nsec = tv.tv_usec * 1000 + (ms % 1000) * 1000000; + ts->tv_sec = tv.tv_sec + ms / 1000; + if (ts->tv_nsec >= 1000000000) { + ts->tv_sec++; + ts->tv_nsec -= 1000000000; + } +} + +int qemu_sem_timedwait(QemuSemaphore *sem, int ms) +{ + int rc; struct timespec ts; - int err; - clock_gettime(CLOCK_REALTIME, &ts); - timespec_add_ms(&ts, msecs); +#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__) + compute_abs_deadline(&ts, ms); + pthread_mutex_lock(&sem->lock); + --sem->count; + while (sem->count < 0) { + rc = pthread_cond_timedwait(&sem->cond, &sem->lock, &ts); + if (rc == ETIMEDOUT) { + break; + } + if (rc != 0) { + error_exit(rc, __func__); + } + } + pthread_mutex_unlock(&sem->lock); + return (rc == ETIMEDOUT ? -1 : 0); +#else + if (ms <= 0) { + /* This is cheaper than sem_timedwait. */ + do { + rc = sem_trywait(&sem->sem); + } while (rc == -1 && errno == EINTR); + if (rc == -1 && errno == EAGAIN) { + return -1; + } + } else { + compute_abs_deadline(&ts, ms); + do { + rc = sem_timedwait(&sem->sem, &ts); + } while (rc == -1 && errno == EINTR); + if (rc == -1 && errno == ETIMEDOUT) { + return -1; + } + } + if (rc < 0) { + error_exit(errno, __func__); + } + return 0; +#endif +} - err = pthread_cond_timedwait(&cond->cond, &mutex->lock, &ts); - if (err && err != ETIMEDOUT) - error_exit(err, __func__); - return err; +void qemu_sem_wait(QemuSemaphore *sem) +{ +#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__) + pthread_mutex_lock(&sem->lock); + --sem->count; + while (sem->count < 0) { + pthread_cond_wait(&sem->cond, &sem->lock); + } + pthread_mutex_unlock(&sem->lock); +#else + int rc; + + do { + rc = sem_wait(&sem->sem); + } while (rc == -1 && errno == EINTR); + if (rc < 0) { + error_exit(errno, __func__); + } +#endif } void qemu_thread_create(QemuThread *thread, void *(*start_routine)(void*), - void *arg) + void *arg, int mode) { + sigset_t set, oldset; int err; + pthread_attr_t attr; - /* Leave signal handling to the iothread. */ - sigset_t set, oldset; + err = pthread_attr_init(&attr); + 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__); + } + } + /* Leave signal handling to the iothread. */ sigfillset(&set); pthread_sigmask(SIG_SETMASK, &set, &oldset); - err = pthread_create(&thread->thread, NULL, start_routine, arg); + err = pthread_create(&thread->thread, &attr, start_routine, arg); if (err) error_exit(err, __func__); pthread_sigmask(SIG_SETMASK, &oldset, NULL); -} - -void qemu_thread_signal(QemuThread *thread, int sig) -{ - int err; - err = pthread_kill(thread->thread, sig); - if (err) - error_exit(err, __func__); + pthread_attr_destroy(&attr); } void qemu_thread_get_self(QemuThread *thread) @@ -185,7 +303,7 @@ void qemu_thread_get_self(QemuThread *thread) thread->thread = pthread_self(); } -int qemu_thread_is_self(QemuThread *thread) +bool qemu_thread_is_self(QemuThread *thread) { return pthread_equal(pthread_self(), thread->thread); } @@ -194,3 +312,15 @@ void qemu_thread_exit(void *retval) { pthread_exit(retval); } + +void *qemu_thread_join(QemuThread *thread) +{ + int err; + void *ret; + + err = pthread_join(thread->thread, &ret); + if (err) { + error_exit(err, __func__); + } + return ret; +}