@@ -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);
@@ -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;
@@ -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. */
@@ -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)
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> --- include/qemu/thread.h | 19 +++++++++++++++++++ util/qemu-thread-posix.c | 41 ++++++++++++++++++++++++++++------------ util/qemu-thread-win32.c | 17 +++++++++++++++++ util/qsp.c | 20 ++++++++++++++++++++ 4 files changed, 85 insertions(+), 12 deletions(-)