mirror of https://gitee.com/openkylin/qemu.git
coroutine: Assert that no locks are held on termination
A coroutine that takes a lock must also release it again. If the coroutine terminates without having released all its locks, it's buggy and we'll probably run into a deadlock sooner or later. Make sure that we don't get such cases. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
parent
0e438cdc93
commit
1b7f01d966
|
@ -39,6 +39,7 @@ struct Coroutine {
|
||||||
void *entry_arg;
|
void *entry_arg;
|
||||||
Coroutine *caller;
|
Coroutine *caller;
|
||||||
QSLIST_ENTRY(Coroutine) pool_next;
|
QSLIST_ENTRY(Coroutine) pool_next;
|
||||||
|
size_t locks_held;
|
||||||
|
|
||||||
/* Coroutines that should be woken up when we yield or terminate */
|
/* Coroutines that should be woken up when we yield or terminate */
|
||||||
QSIMPLEQ_HEAD(, Coroutine) co_queue_wakeup;
|
QSIMPLEQ_HEAD(, Coroutine) co_queue_wakeup;
|
||||||
|
|
|
@ -130,6 +130,7 @@ void coroutine_fn qemu_co_mutex_lock(CoMutex *mutex)
|
||||||
|
|
||||||
mutex->locked = true;
|
mutex->locked = true;
|
||||||
mutex->holder = self;
|
mutex->holder = self;
|
||||||
|
self->locks_held++;
|
||||||
|
|
||||||
trace_qemu_co_mutex_lock_return(mutex, self);
|
trace_qemu_co_mutex_lock_return(mutex, self);
|
||||||
}
|
}
|
||||||
|
@ -146,6 +147,7 @@ void coroutine_fn qemu_co_mutex_unlock(CoMutex *mutex)
|
||||||
|
|
||||||
mutex->locked = false;
|
mutex->locked = false;
|
||||||
mutex->holder = NULL;
|
mutex->holder = NULL;
|
||||||
|
self->locks_held--;
|
||||||
qemu_co_queue_next(&mutex->queue);
|
qemu_co_queue_next(&mutex->queue);
|
||||||
|
|
||||||
trace_qemu_co_mutex_unlock_return(mutex, self);
|
trace_qemu_co_mutex_unlock_return(mutex, self);
|
||||||
|
@ -159,14 +161,19 @@ void qemu_co_rwlock_init(CoRwlock *lock)
|
||||||
|
|
||||||
void qemu_co_rwlock_rdlock(CoRwlock *lock)
|
void qemu_co_rwlock_rdlock(CoRwlock *lock)
|
||||||
{
|
{
|
||||||
|
Coroutine *self = qemu_coroutine_self();
|
||||||
|
|
||||||
while (lock->writer) {
|
while (lock->writer) {
|
||||||
qemu_co_queue_wait(&lock->queue);
|
qemu_co_queue_wait(&lock->queue);
|
||||||
}
|
}
|
||||||
lock->reader++;
|
lock->reader++;
|
||||||
|
self->locks_held++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void qemu_co_rwlock_unlock(CoRwlock *lock)
|
void qemu_co_rwlock_unlock(CoRwlock *lock)
|
||||||
{
|
{
|
||||||
|
Coroutine *self = qemu_coroutine_self();
|
||||||
|
|
||||||
assert(qemu_in_coroutine());
|
assert(qemu_in_coroutine());
|
||||||
if (lock->writer) {
|
if (lock->writer) {
|
||||||
lock->writer = false;
|
lock->writer = false;
|
||||||
|
@ -179,12 +186,16 @@ void qemu_co_rwlock_unlock(CoRwlock *lock)
|
||||||
qemu_co_queue_next(&lock->queue);
|
qemu_co_queue_next(&lock->queue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self->locks_held--;
|
||||||
}
|
}
|
||||||
|
|
||||||
void qemu_co_rwlock_wrlock(CoRwlock *lock)
|
void qemu_co_rwlock_wrlock(CoRwlock *lock)
|
||||||
{
|
{
|
||||||
|
Coroutine *self = qemu_coroutine_self();
|
||||||
|
|
||||||
while (lock->writer || lock->reader) {
|
while (lock->writer || lock->reader) {
|
||||||
qemu_co_queue_wait(&lock->queue);
|
qemu_co_queue_wait(&lock->queue);
|
||||||
}
|
}
|
||||||
lock->writer = true;
|
lock->writer = true;
|
||||||
|
self->locks_held++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,6 +122,7 @@ void qemu_coroutine_enter(Coroutine *co)
|
||||||
case COROUTINE_YIELD:
|
case COROUTINE_YIELD:
|
||||||
return;
|
return;
|
||||||
case COROUTINE_TERMINATE:
|
case COROUTINE_TERMINATE:
|
||||||
|
assert(!co->locks_held);
|
||||||
trace_qemu_coroutine_terminate(co);
|
trace_qemu_coroutine_terminate(co);
|
||||||
coroutine_delete(co);
|
coroutine_delete(co);
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in New Issue