Commit 3dcc9c6e authored by Yury Kotov's avatar Yury Kotov Committed by Paolo Bonzini
Browse files

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: default avatarYury Kotov <yury-kotov@yandex-team.ru>
Message-Id: <20190909131335.16848-2-yury-kotov@yandex-team.ru>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 7a3df11c
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -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);
+29 −12
Original line number Diff line number Diff line
@@ -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;
+17 −0
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
@@ -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)