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>
This commit is contained in:
Yury Kotov 2019-09-09 16:13:33 +03:00 committed by Paolo Bonzini
parent 7a3df11c2a
commit 3dcc9c6ec4
4 changed files with 85 additions and 12 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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. */

View File

@ -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)