semaphore: implement fallback counting semaphores with mutex+condvar

OpenBSD and Darwin do not have sem_timedwait.  Implement a fallback
for them.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
Paolo Bonzini 2012-11-02 15:43:21 +01:00 committed by Anthony Liguori
parent 1f001dc7bc
commit c166cb72f1
2 changed files with 87 additions and 9 deletions

View file

@ -122,36 +122,106 @@ 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;
#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 {
@ -161,15 +231,7 @@ int qemu_sem_timedwait(QemuSemaphore *sem, int ms)
return -1;
}
} else {
struct timeval tv;
struct timespec ts;
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;
}
compute_abs_deadline(&ts, ms);
do {
rc = sem_timedwait(&sem->sem, &ts);
} while (rc == -1 && errno == EINTR);
@ -181,10 +243,19 @@ int qemu_sem_timedwait(QemuSemaphore *sem, int ms)
error_exit(errno, __func__);
}
return 0;
#endif
}
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 {
@ -193,6 +264,7 @@ void qemu_sem_wait(QemuSemaphore *sem)
if (rc < 0) {
error_exit(errno, __func__);
}
#endif
}
void qemu_thread_create(QemuThread *thread,

View file

@ -12,7 +12,13 @@ struct QemuCond {
};
struct QemuSemaphore {
#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__)
pthread_mutex_t lock;
pthread_cond_t cond;
int count;
#else
sem_t sem;
#endif
};
struct QemuThread {