diff options
author | Kevin Wolf <kwolf@redhat.com> | 2016-08-11 17:51:59 +0200 |
---|---|---|
committer | Kevin Wolf <kwolf@redhat.com> | 2016-09-05 19:06:48 +0200 |
commit | 1b7f01d966f97b7820f3cdd471461cf0799a93cc (patch) | |
tree | aaf94f449ee10f7eb018b5f9987e6f1205036c68 | |
parent | 0e438cdc932a785de72166af4641aafa103a6670 (diff) | |
download | qemu-1b7f01d966f97b7820f3cdd471461cf0799a93cc.zip qemu-1b7f01d966f97b7820f3cdd471461cf0799a93cc.tar.gz qemu-1b7f01d966f97b7820f3cdd471461cf0799a93cc.tar.bz2 |
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>
-rw-r--r-- | include/qemu/coroutine_int.h | 1 | ||||
-rw-r--r-- | util/qemu-coroutine-lock.c | 11 | ||||
-rw-r--r-- | util/qemu-coroutine.c | 1 |
3 files changed, 13 insertions, 0 deletions
diff --git a/include/qemu/coroutine_int.h b/include/qemu/coroutine_int.h index 581a7f5..6df9d33 100644 --- a/include/qemu/coroutine_int.h +++ b/include/qemu/coroutine_int.h @@ -39,6 +39,7 @@ struct Coroutine { void *entry_arg; Coroutine *caller; QSLIST_ENTRY(Coroutine) pool_next; + size_t locks_held; /* Coroutines that should be woken up when we yield or terminate */ QSIMPLEQ_HEAD(, Coroutine) co_queue_wakeup; diff --git a/util/qemu-coroutine-lock.c b/util/qemu-coroutine-lock.c index f30ee81..14cf9ce 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++; } diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c index 89f21a9..3cbf225 100644 --- a/util/qemu-coroutine.c +++ b/util/qemu-coroutine.c @@ -122,6 +122,7 @@ void qemu_coroutine_enter(Coroutine *co) case COROUTINE_YIELD: return; case COROUTINE_TERMINATE: + assert(!co->locks_held); trace_qemu_coroutine_terminate(co); coroutine_delete(co); return; |