This patch introduces two lock guard macros that automatically unlock a
QemuMutex:

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

and:

  WITH_QEMU_MUTEX_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 <[email protected]>
---
 include/qemu/thread.h | 26 ++++++++++++++++++++++++++
 util/qemu-timer.c     | 22 ++++++++++------------
 2 files changed, 36 insertions(+), 12 deletions(-)

diff --git a/include/qemu/thread.h b/include/qemu/thread.h
index 3993ab7b25..8e8254f94f 100644
--- a/include/qemu/thread.h
+++ b/include/qemu/thread.h
@@ -119,6 +119,32 @@ static inline void (qemu_mutex_unlock)(QemuMutex *mutex)
     qemu_mutex_unlock(mutex);
 }
 
+static inline QemuMutex *qemu_mutex_auto_lock(QemuMutex *mutex)
+{
+    qemu_mutex_lock(mutex);
+    return mutex;
+}
+
+static inline void qemu_mutex_auto_unlock(QemuMutex *mutex)
+{
+    if (mutex) {
+        qemu_mutex_unlock(mutex);
+    }
+}
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(QemuMutex, qemu_mutex_auto_unlock)
+
+#define WITH_QEMU_MUTEX_LOCK_GUARD_(mutex, var) \
+    for (g_autoptr(QemuMutex) var = qemu_mutex_auto_lock((mutex)); \
+         var; qemu_mutex_auto_unlock(var), var = NULL)
+
+#define WITH_QEMU_MUTEX_LOCK_GUARD(mutex) \
+    WITH_QEMU_MUTEX_LOCK_GUARD_(mutex, qemu_mutex_auto##__COUNTER__)
+
+#define QEMU_MUTEX_LOCK_GUARD(mutex) \
+    g_autoptr(QemuMutex) qemu_mutex_auto##__COUNTER__ = \
+            qemu_mutex_auto_lock((mutex))
+
 static inline void (qemu_rec_mutex_lock)(QemuRecMutex *mutex)
 {
     qemu_rec_mutex_lock(mutex);
diff --git a/util/qemu-timer.c b/util/qemu-timer.c
index ef52d28d37..4c42d33cf5 100644
--- a/util/qemu-timer.c
+++ b/util/qemu-timer.c
@@ -186,13 +186,12 @@ bool timerlist_expired(QEMUTimerList *timer_list)
         return false;
     }
 
-    qemu_mutex_lock(&timer_list->active_timers_lock);
-    if (!timer_list->active_timers) {
-        qemu_mutex_unlock(&timer_list->active_timers_lock);
-        return false;
+    WITH_QEMU_MUTEX_LOCK_GUARD(&timer_list->active_timers_lock) {
+        if (!timer_list->active_timers) {
+            return false;
+        }
+        expire_time = timer_list->active_timers->expire_time;
     }
-    expire_time = timer_list->active_timers->expire_time;
-    qemu_mutex_unlock(&timer_list->active_timers_lock);
 
     return expire_time <= qemu_clock_get_ns(timer_list->clock->type);
 }
@@ -225,13 +224,12 @@ int64_t timerlist_deadline_ns(QEMUTimerList *timer_list)
      * value but ->notify_cb() is called when the deadline changes.  Therefore
      * the caller should notice the change and there is no race condition.
      */
-    qemu_mutex_lock(&timer_list->active_timers_lock);
-    if (!timer_list->active_timers) {
-        qemu_mutex_unlock(&timer_list->active_timers_lock);
-        return -1;
+    WITH_QEMU_MUTEX_LOCK_GUARD(&timer_list->active_timers_lock) {
+        if (!timer_list->active_timers) {
+            return -1;
+        }
+        expire_time = timer_list->active_timers->expire_time;
     }
-    expire_time = timer_list->active_timers->expire_time;
-    qemu_mutex_unlock(&timer_list->active_timers_lock);
 
     delta = expire_time - qemu_clock_get_ns(timer_list->clock->type);
 
-- 
2.24.1

Reply via email to