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; | ||||
|     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; | ||||
|  | ||||
| @ -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++; | ||||
| } | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Kevin Wolf
						Kevin Wolf