From 1b7f01d966f97b7820f3cdd471461cf0799a93cc Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 11 Aug 2016 17:51:59 +0200 Subject: 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 Reviewed-by: Paolo Bonzini Reviewed-by: Stefan Hajnoczi --- util/qemu-coroutine-lock.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'util/qemu-coroutine-lock.c') diff --git a/util/qemu-coroutine-lock.c b/util/qemu-coroutine-lock.c index f30ee8184d..14cf9ce458 100644 --- a/util/qemu-coroutine-lock.c +++ b/util/qemu-coroutine-lock.c @@ -130,6 +130,7 @@ void coroutine_fn qemu_co_mutex_lock(CoMutex *mutex) mutex->locked = true; mutex->holder = self; + self->locks_held++; 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->holder = NULL; + self->locks_held--; qemu_co_queue_next(&mutex->queue); 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) { + Coroutine *self = qemu_coroutine_self(); + while (lock->writer) { qemu_co_queue_wait(&lock->queue); } lock->reader++; + self->locks_held++; } void qemu_co_rwlock_unlock(CoRwlock *lock) { + Coroutine *self = qemu_coroutine_self(); + assert(qemu_in_coroutine()); if (lock->writer) { lock->writer = false; @@ -179,12 +186,16 @@ void qemu_co_rwlock_unlock(CoRwlock *lock) qemu_co_queue_next(&lock->queue); } } + self->locks_held--; } void qemu_co_rwlock_wrlock(CoRwlock *lock) { + Coroutine *self = qemu_coroutine_self(); + while (lock->writer || lock->reader) { qemu_co_queue_wait(&lock->queue); } lock->writer = true; + self->locks_held++; } -- cgit v1.2.3