aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYury Kotov <yury-kotov@yandex-team.ru>2019-09-09 16:13:33 +0300
committerPaolo Bonzini <pbonzini@redhat.com>2019-09-16 17:13:06 +0200
commit3dcc9c6ec4ea60fd1464b35aa82199483f24ba75 (patch)
treea5783dd0cfda9df2e82aa63a3be577a913e86ec1
parent7a3df11c2a647cf889f6ede8b7d5f81438bb5cc9 (diff)
qemu-thread: Add qemu_cond_timedwait
The new function is needed to implement conditional sleep for CPU throttling. It's possible to reuse qemu_sem_timedwait, but it's more difficult than just add qemu_cond_timedwait. Also moved compute_abs_deadline function up the code to reuse it in qemu_cond_timedwait_impl win32. Signed-off-by: Yury Kotov <yury-kotov@yandex-team.ru> Message-Id: <20190909131335.16848-2-yury-kotov@yandex-team.ru> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--include/qemu/thread.h19
-rw-r--r--util/qemu-thread-posix.c41
-rw-r--r--util/qemu-thread-win32.c17
-rw-r--r--util/qsp.c20
4 files changed, 85 insertions, 12 deletions
diff --git a/include/qemu/thread.h b/include/qemu/thread.h
index 55d83a907c..047db0307e 100644
--- a/include/qemu/thread.h
+++ b/include/qemu/thread.h
@@ -34,6 +34,8 @@ typedef void (*QemuRecMutexLockFunc)(QemuRecMutex *m, const char *f, int l);
typedef int (*QemuRecMutexTrylockFunc)(QemuRecMutex *m, const char *f, int l);
typedef void (*QemuCondWaitFunc)(QemuCond *c, QemuMutex *m, const char *f,
int l);
+typedef bool (*QemuCondTimedWaitFunc)(QemuCond *c, QemuMutex *m, int ms,
+ const char *f, int l);
extern QemuMutexLockFunc qemu_bql_mutex_lock_func;
extern QemuMutexLockFunc qemu_mutex_lock_func;
@@ -41,6 +43,7 @@ extern QemuMutexTrylockFunc qemu_mutex_trylock_func;
extern QemuRecMutexLockFunc qemu_rec_mutex_lock_func;
extern QemuRecMutexTrylockFunc qemu_rec_mutex_trylock_func;
extern QemuCondWaitFunc qemu_cond_wait_func;
+extern QemuCondTimedWaitFunc qemu_cond_timedwait_func;
/* convenience macros to bypass the profiler */
#define qemu_mutex_lock__raw(m) \
@@ -63,6 +66,8 @@ extern QemuCondWaitFunc qemu_cond_wait_func;
qemu_rec_mutex_trylock_impl(m, __FILE__, __LINE__);
#define qemu_cond_wait(c, m) \
qemu_cond_wait_impl(c, m, __FILE__, __LINE__);
+#define qemu_cond_timedwait(c, m, ms) \
+ qemu_cond_wait_impl(c, m, ms, __FILE__, __LINE__);
#else
#define qemu_mutex_lock(m) ({ \
QemuMutexLockFunc _f = atomic_read(&qemu_mutex_lock_func); \
@@ -89,6 +94,11 @@ extern QemuCondWaitFunc qemu_cond_wait_func;
QemuCondWaitFunc _f = atomic_read(&qemu_cond_wait_func); \
_f(c, m, __FILE__, __LINE__); \
})
+
+#define qemu_cond_timedwait(c, m, ms) ({ \
+ QemuCondTimedWaitFunc _f = atomic_read(&qemu_cond_timedwait_func); \
+ _f(c, m, ms, __FILE__, __LINE__); \
+ })
#endif
#define qemu_mutex_unlock(mutex) \
@@ -134,12 +144,21 @@ void qemu_cond_signal(QemuCond *cond);
void qemu_cond_broadcast(QemuCond *cond);
void qemu_cond_wait_impl(QemuCond *cond, QemuMutex *mutex,
const char *file, const int line);
+bool qemu_cond_timedwait_impl(QemuCond *cond, QemuMutex *mutex, int ms,
+ const char *file, const int line);
static inline void (qemu_cond_wait)(QemuCond *cond, QemuMutex *mutex)
{
qemu_cond_wait(cond, mutex);
}
+/* Returns true if timeout has not expired, and false otherwise */
+static inline bool (qemu_cond_timedwait)(QemuCond *cond, QemuMutex *mutex,
+ int ms)
+{
+ return qemu_cond_timedwait(cond, mutex, ms);
+}
+
void qemu_sem_init(QemuSemaphore *sem, int init);
void qemu_sem_post(QemuSemaphore *sem);
void qemu_sem_wait(QemuSemaphore *sem);
diff --git a/util/qemu-thread-posix.c b/util/qemu-thread-posix.c
index 1bf5e65dea..838980aaa5 100644
--- a/util/qemu-thread-posix.c
+++ b/util/qemu-thread-posix.c
@@ -36,6 +36,18 @@ static void error_exit(int err, const char *msg)
abort();
}
+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;
+ }
+}
+
void qemu_mutex_init(QemuMutex *mutex)
{
int err;
@@ -164,6 +176,23 @@ void qemu_cond_wait_impl(QemuCond *cond, QemuMutex *mutex, const char *file, con
error_exit(err, __func__);
}
+bool qemu_cond_timedwait_impl(QemuCond *cond, QemuMutex *mutex, int ms,
+ const char *file, const int line)
+{
+ int err;
+ struct timespec ts;
+
+ assert(cond->initialized);
+ trace_qemu_mutex_unlock(mutex, file, line);
+ compute_abs_deadline(&ts, ms);
+ err = pthread_cond_timedwait(&cond->cond, &mutex->lock, &ts);
+ trace_qemu_mutex_locked(mutex, file, line);
+ if (err && err != ETIMEDOUT) {
+ error_exit(err, __func__);
+ }
+ return err != ETIMEDOUT;
+}
+
void qemu_sem_init(QemuSemaphore *sem, int init)
{
int rc;
@@ -238,18 +267,6 @@ void qemu_sem_post(QemuSemaphore *sem)
#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;
diff --git a/util/qemu-thread-win32.c b/util/qemu-thread-win32.c
index 572f88535d..56a83333da 100644
--- a/util/qemu-thread-win32.c
+++ b/util/qemu-thread-win32.c
@@ -145,6 +145,23 @@ void qemu_cond_wait_impl(QemuCond *cond, QemuMutex *mutex, const char *file, con
qemu_mutex_post_lock(mutex, file, line);
}
+bool qemu_cond_timedwait_impl(QemuCond *cond, QemuMutex *mutex, int ms,
+ const char *file, const int line)
+{
+ int rc = 0;
+
+ assert(cond->initialized);
+ trace_qemu_mutex_unlock(mutex, file, line);
+ if (!SleepConditionVariableSRW(&cond->var, &mutex->lock, ms, 0)) {
+ rc = GetLastError();
+ }
+ trace_qemu_mutex_locked(mutex, file, line);
+ if (rc && rc != ERROR_TIMEOUT) {
+ error_exit(rc, __func__);
+ }
+ return rc != ERROR_TIMEOUT;
+}
+
void qemu_sem_init(QemuSemaphore *sem, int init)
{
/* Manual reset. */
diff --git a/util/qsp.c b/util/qsp.c
index 5264c97342..62265417fd 100644
--- a/util/qsp.c
+++ b/util/qsp.c
@@ -131,6 +131,7 @@ QemuRecMutexLockFunc qemu_rec_mutex_lock_func = qemu_rec_mutex_lock_impl;
QemuRecMutexTrylockFunc qemu_rec_mutex_trylock_func =
qemu_rec_mutex_trylock_impl;
QemuCondWaitFunc qemu_cond_wait_func = qemu_cond_wait_impl;
+QemuCondTimedWaitFunc qemu_cond_timedwait_func = qemu_cond_timedwait_impl;
/*
* It pays off to _not_ hash callsite->file; hashing a string is slow, and
@@ -412,6 +413,23 @@ qsp_cond_wait(QemuCond *cond, QemuMutex *mutex, const char *file, int line)
qsp_entry_record(e, t1 - t0);
}
+static bool
+qsp_cond_timedwait(QemuCond *cond, QemuMutex *mutex, int ms,
+ const char *file, int line)
+{
+ QSPEntry *e;
+ int64_t t0, t1;
+ bool ret;
+
+ t0 = get_clock();
+ ret = qemu_cond_timedwait_impl(cond, mutex, ms, file, line);
+ t1 = get_clock();
+
+ e = qsp_entry_get(cond, file, line, QSP_CONDVAR);
+ qsp_entry_record(e, t1 - t0);
+ return ret;
+}
+
bool qsp_is_enabled(void)
{
return atomic_read(&qemu_mutex_lock_func) == qsp_mutex_lock;
@@ -425,6 +443,7 @@ void qsp_enable(void)
atomic_set(&qemu_rec_mutex_lock_func, qsp_rec_mutex_lock);
atomic_set(&qemu_rec_mutex_trylock_func, qsp_rec_mutex_trylock);
atomic_set(&qemu_cond_wait_func, qsp_cond_wait);
+ atomic_set(&qemu_cond_timedwait_func, qsp_cond_timedwait);
}
void qsp_disable(void)
@@ -435,6 +454,7 @@ void qsp_disable(void)
atomic_set(&qemu_rec_mutex_lock_func, qemu_rec_mutex_lock_impl);
atomic_set(&qemu_rec_mutex_trylock_func, qemu_rec_mutex_trylock_impl);
atomic_set(&qemu_cond_wait_func, qemu_cond_wait_impl);
+ atomic_set(&qemu_cond_timedwait_func, qemu_cond_timedwait_impl);
}
static gint qsp_tree_cmp(gconstpointer ap, gconstpointer bp, gpointer up)