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:
parent
7a3df11c2a
commit
3dcc9c6ec4
|
@ -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. */
|
||||
|
|
20
util/qsp.c
20
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)
|
||||
|
|
Loading…
Reference in a new issue