Skip to content

Commit

Permalink
coroutine-lock: convert CoQueue to use QemuLockable
Browse files Browse the repository at this point in the history
There are cases in which a queued coroutine must be restarted from
non-coroutine context (with qemu_co_enter_next).  In this cases,
qemu_co_enter_next also needs to be thread-safe, but it cannot use
a CoMutex and so cannot qemu_co_queue_wait.  Use QemuLockable so
that the CoQueue can interchangeably use CoMutex or QemuMutex.

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20180203153935.8056-4-pbonzini@redhat.com>
Reviewed-by: Fam Zheng <famz@redhat.com>
Signed-off-by: Fam Zheng <famz@redhat.com>
  • Loading branch information
bonzini authored and Fam Zheng committed Feb 8, 2018
1 parent e70372f commit 1a957cf
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 6 deletions.
6 changes: 5 additions & 1 deletion include/qemu/coroutine.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,9 @@ void qemu_co_queue_init(CoQueue *queue);
* caller of the coroutine. The mutex is unlocked during the wait and
* locked again afterwards.
*/
void coroutine_fn qemu_co_queue_wait(CoQueue *queue, CoMutex *mutex);
#define qemu_co_queue_wait(queue, lock) \
qemu_co_queue_wait_impl(queue, QEMU_MAKE_LOCKABLE(lock))
void coroutine_fn qemu_co_queue_wait_impl(CoQueue *queue, QemuLockable *lock);

/**
* Restarts the next coroutine in the CoQueue and removes it from the queue.
Expand Down Expand Up @@ -271,4 +273,6 @@ void coroutine_fn qemu_co_sleep_ns(QEMUClockType type, int64_t ns);
*/
void coroutine_fn yield_until_fd_readable(int fd);

#include "qemu/lockable.h"

#endif /* QEMU_COROUTINE_H */
12 changes: 7 additions & 5 deletions util/qemu-coroutine-lock.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ void qemu_co_queue_init(CoQueue *queue)
QSIMPLEQ_INIT(&queue->entries);
}

void coroutine_fn qemu_co_queue_wait(CoQueue *queue, CoMutex *mutex)
void coroutine_fn qemu_co_queue_wait_impl(CoQueue *queue, QemuLockable *lock)
{
Coroutine *self = qemu_coroutine_self();
QSIMPLEQ_INSERT_TAIL(&queue->entries, self, co_queue_next);

if (mutex) {
qemu_co_mutex_unlock(mutex);
if (lock) {
qemu_lockable_unlock(lock);
}

/* There is no race condition here. Other threads will call
Expand All @@ -60,9 +60,11 @@ void coroutine_fn qemu_co_queue_wait(CoQueue *queue, CoMutex *mutex)
/* TODO: OSv implements wait morphing here, where the wakeup
* primitive automatically places the woken coroutine on the
* mutex's queue. This avoids the thundering herd effect.
* This could be implemented for CoMutexes, but not really for
* other cases of QemuLockable.
*/
if (mutex) {
qemu_co_mutex_lock(mutex);
if (lock) {
qemu_lockable_lock(lock);
}
}

Expand Down

0 comments on commit 1a957cf

Please sign in to comment.