qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

lockable: add lock guards

This patch introduces two lock guard macros that automatically unlock a
lock object (QemuMutex and others):

void f(void) {
QEMU_LOCK_GUARD(&mutex);
if (!may_fail()) {
return; /* automatically unlocks mutex */
}
...
}

and:

WITH_QEMU_LOCK_GUARD(&mutex) {
if (!may_fail()) {
return; /* automatically unlocks mutex */
}
}
/* automatically unlocks mutex here */
...

Convert qemu-timer.c functions that benefit from these macros as an
example. Manual qemu_mutex_lock/unlock() callers are left unmodified in
cases where clarity would not improve by switching to the macros.

Many other QemuMutex users remain in the codebase that might benefit
from lock guards. Over time they can be converted, if that is
desirable.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
[Use QEMU_MAKE_LOCKABLE_NONNULL. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

authored by

Stefan Hajnoczi and committed by
Paolo Bonzini
3284c3dd 8834dcf4

+76 -12
+65
include/qemu/lockable.h
··· 106 106 x->unlock(x->object); 107 107 } 108 108 109 + static inline QemuLockable *qemu_lockable_auto_lock(QemuLockable *x) 110 + { 111 + qemu_lockable_lock(x); 112 + return x; 113 + } 114 + 115 + static inline void qemu_lockable_auto_unlock(QemuLockable *x) 116 + { 117 + if (x) { 118 + qemu_lockable_unlock(x); 119 + } 120 + } 121 + 122 + G_DEFINE_AUTOPTR_CLEANUP_FUNC(QemuLockable, qemu_lockable_auto_unlock) 123 + 124 + #define WITH_QEMU_LOCK_GUARD_(x, var) \ 125 + for (g_autoptr(QemuLockable) var = \ 126 + qemu_lockable_auto_lock(QEMU_MAKE_LOCKABLE_NONNULL((x))); \ 127 + var; \ 128 + qemu_lockable_auto_unlock(var), var = NULL) 129 + 130 + /** 131 + * WITH_QEMU_LOCK_GUARD - Lock a lock object for scope 132 + * 133 + * @x: a lock object (currently one of QemuMutex, CoMutex, QemuSpin). 134 + * 135 + * This macro defines a lock scope such that entering the scope takes the lock 136 + * and leaving the scope releases the lock. Return statements are allowed 137 + * within the scope and release the lock. Break and continue statements leave 138 + * the scope early and release the lock. 139 + * 140 + * WITH_QEMU_LOCK_GUARD(&mutex) { 141 + * ... 142 + * if (error) { 143 + * return; <-- mutex is automatically unlocked 144 + * } 145 + * 146 + * if (early_exit) { 147 + * break; <-- leave this scope early 148 + * } 149 + * ... 150 + * } 151 + */ 152 + #define WITH_QEMU_LOCK_GUARD(x) \ 153 + WITH_QEMU_LOCK_GUARD_((x), qemu_lockable_auto##__COUNTER__) 154 + 155 + /** 156 + * QEMU_LOCK_GUARD - Lock an object until the end of the scope 157 + * 158 + * @x: a lock object (currently one of QemuMutex, CoMutex, QemuSpin). 159 + * 160 + * This macro takes a lock until the end of the scope. Return statements 161 + * release the lock. 162 + * 163 + * ... <-- mutex not locked 164 + * QEMU_LOCK_GUARD(&mutex); <-- mutex locked from here onwards 165 + * ... 166 + * if (error) { 167 + * return; <-- mutex is automatically unlocked 168 + * } 169 + */ 170 + #define QEMU_LOCK_GUARD(x) \ 171 + g_autoptr(QemuLockable) qemu_lockable_auto##__COUNTER__ = \ 172 + qemu_lockable_auto_lock(QEMU_MAKE_LOCKABLE((x))) 173 + 109 174 #endif
+11 -12
util/qemu-timer.c
··· 25 25 #include "qemu/osdep.h" 26 26 #include "qemu/main-loop.h" 27 27 #include "qemu/timer.h" 28 + #include "qemu/lockable.h" 28 29 #include "sysemu/replay.h" 29 30 #include "sysemu/cpus.h" 30 31 ··· 186 187 return false; 187 188 } 188 189 189 - qemu_mutex_lock(&timer_list->active_timers_lock); 190 - if (!timer_list->active_timers) { 191 - qemu_mutex_unlock(&timer_list->active_timers_lock); 192 - return false; 190 + WITH_QEMU_LOCK_GUARD(&timer_list->active_timers_lock) { 191 + if (!timer_list->active_timers) { 192 + return false; 193 + } 194 + expire_time = timer_list->active_timers->expire_time; 193 195 } 194 - expire_time = timer_list->active_timers->expire_time; 195 - qemu_mutex_unlock(&timer_list->active_timers_lock); 196 196 197 197 return expire_time <= qemu_clock_get_ns(timer_list->clock->type); 198 198 } ··· 225 225 * value but ->notify_cb() is called when the deadline changes. Therefore 226 226 * the caller should notice the change and there is no race condition. 227 227 */ 228 - qemu_mutex_lock(&timer_list->active_timers_lock); 229 - if (!timer_list->active_timers) { 230 - qemu_mutex_unlock(&timer_list->active_timers_lock); 231 - return -1; 228 + WITH_QEMU_LOCK_GUARD(&timer_list->active_timers_lock) { 229 + if (!timer_list->active_timers) { 230 + return -1; 231 + } 232 + expire_time = timer_list->active_timers->expire_time; 232 233 } 233 - expire_time = timer_list->active_timers->expire_time; 234 - qemu_mutex_unlock(&timer_list->active_timers_lock); 235 234 236 235 delta = expire_time - qemu_clock_get_ns(timer_list->clock->type); 237 236