qemu_event_timedwait() is equivalent to qemu_event_wait(), except it has
a relative timeout.
Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
---
include/qemu/thread-posix.h | 11 +++++++++++
include/qemu/thread.h | 8 +++++++-
util/event.c | 34 +++++++++++++++++++++++++++++-----
util/qemu-thread-posix.c | 11 +----------
4 files changed, 48 insertions(+), 16 deletions(-)
diff --git a/include/qemu/thread-posix.h b/include/qemu/thread-posix.h
index 758808b705e4..11193b1580f8 100644
--- a/include/qemu/thread-posix.h
+++ b/include/qemu/thread-posix.h
@@ -36,4 +36,15 @@ struct QemuThread {
pthread_t thread;
};
+static inline clockid_t qemu_timedwait_clockid(void)
+{
+#ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK
+ return CLOCK_MONOTONIC;
+#else
+ return CLOCK_REALTIME;
+#endif
+}
+
+void compute_abs_deadline(struct timespec *ts, int ms);
+
#endif
diff --git a/include/qemu/thread.h b/include/qemu/thread.h
index f0302ed01fdb..3030458bb666 100644
--- a/include/qemu/thread.h
+++ b/include/qemu/thread.h
@@ -201,7 +201,13 @@ void qemu_sem_destroy(QemuSemaphore *sem);
void qemu_event_init(QemuEvent *ev, bool init);
void qemu_event_set(QemuEvent *ev);
void qemu_event_reset(QemuEvent *ev);
-void qemu_event_wait(QemuEvent *ev);
+bool qemu_event_timedwait(QemuEvent *ev, int ms);
+
+static inline void qemu_event_wait(QemuEvent *ev)
+{
+ qemu_event_timedwait(ev, INT_MAX);
+}
+
void qemu_event_destroy(QemuEvent *ev);
void qemu_thread_create(QemuThread *thread, const char *name,
diff --git a/util/event.c b/util/event.c
index 5a8141cd0e46..e22cc08a629b 100644
--- a/util/event.c
+++ b/util/event.c
@@ -33,7 +33,15 @@ void qemu_event_init(QemuEvent *ev, bool init)
{
#ifndef HAVE_FUTEX
pthread_mutex_init(&ev->lock, NULL);
+#ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK
+ pthread_condattr_t attr;
+ pthread_condattr_init(&attr);
+ pthread_condattr_setclock(&attr, qemu_timedwait_clockid());
+ pthread_cond_init(&ev->cond, &attr);
+ pthread_condattr_destroy(&attr);
+#else
pthread_cond_init(&ev->cond, NULL);
+#endif
#endif
ev->value = (init ? EV_SET : EV_FREE);
@@ -121,15 +129,17 @@ void qemu_event_reset(QemuEvent *ev)
#endif
}
-void qemu_event_wait(QemuEvent *ev)
+bool qemu_event_timedwait(QemuEvent *ev, int ms)
{
assert(ev->initialized);
#ifdef HAVE_FUTEX
+ int64_t deadline = get_clock() + (int64_t)ms * SCALE_MS;
+
while (true) {
/*
- * qemu_event_wait must synchronize with qemu_event_set even if it does
- * not go down the slow path, so this load-acquire is needed that
+ * qemu_event_timedwait must synchronize with qemu_event_set even if it
+ * does not go down the slow path, so this load-acquire is needed that
* synchronizes with the first memory barrier in qemu_event_set().
*/
unsigned value = qatomic_load_acquire(&ev->value);
@@ -159,13 +169,27 @@ void qemu_event_wait(QemuEvent *ev)
* a smp_mb() pairing with the second barrier of qemu_event_set().
* The barrier is inside the FUTEX_WAIT system call.
*/
- qemu_futex_wait(ev, EV_BUSY);
+ if (!qemu_futex_timedwait(ev, EV_BUSY, deadline)) {
+ return false;
+ }
}
+
+ return true;
#else
+ bool failed;
+ struct timespec ts;
+
+ compute_abs_deadline(&ts, ms);
+
pthread_mutex_lock(&ev->lock);
while (qatomic_read(&ev->value) != EV_SET) {
- pthread_cond_wait(&ev->cond, &ev->lock);
+ failed = pthread_cond_timedwait(&ev->cond, &ev->lock, &ts);
+ if (failed) {
+ break;
+ }
}
pthread_mutex_unlock(&ev->lock);
+
+ return !failed;
#endif
}
diff --git a/util/qemu-thread-posix.c b/util/qemu-thread-posix.c
index ba725444ba63..f649bfa00015 100644
--- a/util/qemu-thread-posix.c
+++ b/util/qemu-thread-posix.c
@@ -44,16 +44,7 @@ static void error_exit(int err, const char *msg)
abort();
}
-static inline clockid_t qemu_timedwait_clockid(void)
-{
-#ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK
- return CLOCK_MONOTONIC;
-#else
- return CLOCK_REALTIME;
-#endif
-}
-
-static void compute_abs_deadline(struct timespec *ts, int ms)
+void compute_abs_deadline(struct timespec *ts, int ms)
{
clock_gettime(qemu_timedwait_clockid(), ts);
ts->tv_nsec += (ms % 1000) * 1000000;
--
2.51.0