mirror of
https://github.com/qemu/qemu.git
synced 2024-11-25 20:03:37 +08:00
coroutine-lock: convert CoQueue to use QemuLockable
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>
This commit is contained in:
parent
e70372fcaf
commit
1a957cf9c4
@ -183,7 +183,9 @@ void qemu_co_queue_init(CoQueue *queue);
|
|||||||
* caller of the coroutine. The mutex is unlocked during the wait and
|
* caller of the coroutine. The mutex is unlocked during the wait and
|
||||||
* locked again afterwards.
|
* 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.
|
* Restarts the next coroutine in the CoQueue and removes it from the queue.
|
||||||
@ -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);
|
void coroutine_fn yield_until_fd_readable(int fd);
|
||||||
|
|
||||||
|
#include "qemu/lockable.h"
|
||||||
|
|
||||||
#endif /* QEMU_COROUTINE_H */
|
#endif /* QEMU_COROUTINE_H */
|
||||||
|
@ -40,13 +40,13 @@ void qemu_co_queue_init(CoQueue *queue)
|
|||||||
QSIMPLEQ_INIT(&queue->entries);
|
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();
|
Coroutine *self = qemu_coroutine_self();
|
||||||
QSIMPLEQ_INSERT_TAIL(&queue->entries, self, co_queue_next);
|
QSIMPLEQ_INSERT_TAIL(&queue->entries, self, co_queue_next);
|
||||||
|
|
||||||
if (mutex) {
|
if (lock) {
|
||||||
qemu_co_mutex_unlock(mutex);
|
qemu_lockable_unlock(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* There is no race condition here. Other threads will call
|
/* There is no race condition here. Other threads will call
|
||||||
@ -60,9 +60,11 @@ void coroutine_fn qemu_co_queue_wait(CoQueue *queue, CoMutex *mutex)
|
|||||||
/* TODO: OSv implements wait morphing here, where the wakeup
|
/* TODO: OSv implements wait morphing here, where the wakeup
|
||||||
* primitive automatically places the woken coroutine on the
|
* primitive automatically places the woken coroutine on the
|
||||||
* mutex's queue. This avoids the thundering herd effect.
|
* 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) {
|
if (lock) {
|
||||||
qemu_co_mutex_lock(mutex);
|
qemu_lockable_lock(lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user