All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/2] thread: add lock guard macros
@ 2020-03-16 11:09 Stefan Hajnoczi
  2020-03-16 11:09 ` [PATCH v2 1/2] lockable: add lock guards Stefan Hajnoczi
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Stefan Hajnoczi @ 2020-03-16 11:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Paolo Bonzini, Alex Bennée, Markus Armbruster,
	Stefan Hajnoczi, Dr. David Alan Gilbert

Lock guards automatically call qemu_(rec_)mutex_unlock() when returning from a
function or leaving leaving a lexical scope.  This simplifies code and
eliminates leaks (especially in error code paths).

This series adds lock guards for QemuMutex and QemuRecMutex.  It does not
convert the entire tree but includes example conversions.

Stefan Hajnoczi (2):
  lockable: add lock guards
  lockable: add QemuRecMutex support

 include/qemu/lockable.h | 67 +++++++++++++++++++++++++++++++++++++++++
 plugins/core.c          |  7 ++---
 plugins/loader.c        | 16 +++++-----
 util/qemu-timer.c       | 23 +++++++-------
 4 files changed, 89 insertions(+), 24 deletions(-)

-- 
2.24.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v2 1/2] lockable: add lock guards
  2020-03-16 11:09 [PATCH v2 0/2] thread: add lock guard macros Stefan Hajnoczi
@ 2020-03-16 11:09 ` Stefan Hajnoczi
  2020-03-16 11:09 ` [PATCH v2 2/2] lockable: add QemuRecMutex support Stefan Hajnoczi
  2020-03-16 11:29 ` [PATCH v2 0/2] thread: add lock guard macros Paolo Bonzini
  2 siblings, 0 replies; 4+ messages in thread
From: Stefan Hajnoczi @ 2020-03-16 11:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Paolo Bonzini, Alex Bennée, Markus Armbruster,
	Stefan Hajnoczi, Dr. David Alan Gilbert

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>
---
 include/qemu/lockable.h | 65 +++++++++++++++++++++++++++++++++++++++++
 util/qemu-timer.c       | 23 +++++++--------
 2 files changed, 76 insertions(+), 12 deletions(-)

diff --git a/include/qemu/lockable.h b/include/qemu/lockable.h
index 84ea794bcf..2b52c7c1e5 100644
--- a/include/qemu/lockable.h
+++ b/include/qemu/lockable.h
@@ -93,4 +93,69 @@ static inline void qemu_lockable_unlock(QemuLockable *x)
     x->unlock(x->object);
 }
 
+static inline QemuLockable *qemu_lockable_auto_lock(QemuLockable *x)
+{
+    qemu_lockable_lock(x);
+    return x;
+}
+
+static inline void qemu_lockable_auto_unlock(QemuLockable *x)
+{
+    if (x) {
+        qemu_lockable_unlock(x);
+    }
+}
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(QemuLockable, qemu_lockable_auto_unlock)
+
+#define WITH_QEMU_LOCK_GUARD_(x, var) \
+    for (g_autoptr(QemuLockable) var = \
+                qemu_lockable_auto_lock(QEMU_MAKE_LOCKABLE((x))); \
+         var; \
+         qemu_lockable_auto_unlock(var), var = NULL)
+
+/**
+ * WITH_QEMU_LOCK_GUARD - Lock a lock object for scope
+ *
+ * @x: a lock object (currently one of QemuMutex, CoMutex, QemuSpin).
+ *
+ * This macro defines a lock scope such that entering the scope takes the lock
+ * and leaving the scope releases the lock.  Return statements are allowed
+ * within the scope and release the lock.  Break and continue statements leave
+ * the scope early and release the lock.
+ *
+ *   WITH_QEMU_LOCK_GUARD(&mutex) {
+ *       ...
+ *       if (error) {
+ *           return; <-- mutex is automatically unlocked
+ *       }
+ *
+ *       if (early_exit) {
+ *           break;  <-- leave this scope early
+ *       }
+ *       ...
+ *   }
+ */
+#define WITH_QEMU_LOCK_GUARD(x) \
+    WITH_QEMU_LOCK_GUARD_((x), qemu_lockable_auto##__COUNTER__)
+
+/**
+ * QEMU_LOCK_GUARD - Lock an object until the end of the scope
+ *
+ * @x: a lock object (currently one of QemuMutex, CoMutex, QemuSpin).
+ *
+ * This macro takes a lock until the end of the scope.  Return statements
+ * release the lock.
+ *
+ *   ... <-- mutex not locked
+ *   QEMU_LOCK_GUARD(&mutex); <-- mutex locked from here onwards
+ *   ...
+ *   if (error) {
+ *       return; <-- mutex is automatically unlocked
+ *   }
+ */
+#define QEMU_LOCK_GUARD(x) \
+    g_autoptr(QemuLockable) qemu_lockable_auto##__COUNTER__ = \
+            qemu_lockable_auto_lock(QEMU_MAKE_LOCKABLE((x)))
+
 #endif
diff --git a/util/qemu-timer.c b/util/qemu-timer.c
index ef52d28d37..d548d3c1ad 100644
--- a/util/qemu-timer.c
+++ b/util/qemu-timer.c
@@ -25,6 +25,7 @@
 #include "qemu/osdep.h"
 #include "qemu/main-loop.h"
 #include "qemu/timer.h"
+#include "qemu/lockable.h"
 #include "sysemu/replay.h"
 #include "sysemu/cpus.h"
 
@@ -186,13 +187,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_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 +225,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_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


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v2 2/2] lockable: add QemuRecMutex support
  2020-03-16 11:09 [PATCH v2 0/2] thread: add lock guard macros Stefan Hajnoczi
  2020-03-16 11:09 ` [PATCH v2 1/2] lockable: add lock guards Stefan Hajnoczi
@ 2020-03-16 11:09 ` Stefan Hajnoczi
  2020-03-16 11:29 ` [PATCH v2 0/2] thread: add lock guard macros Paolo Bonzini
  2 siblings, 0 replies; 4+ messages in thread
From: Stefan Hajnoczi @ 2020-03-16 11:09 UTC (permalink / raw)
  To: qemu-devel
  Cc: Paolo Bonzini, Alex Bennée, Markus Armbruster,
	Stefan Hajnoczi, Dr. David Alan Gilbert

The polymorphic locking macros don't support QemuRecMutex yet.  Add it
so that lock guards can be used with QemuRecMutex.

Convert TCG plugins functions that benefit from these macros.  Manual
qemu_rec_mutex_lock/unlock() callers are left unmodified in cases where
clarity would not improve by switching to the macros.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 include/qemu/lockable.h |  2 ++
 plugins/core.c          |  7 +++----
 plugins/loader.c        | 16 ++++++++--------
 3 files changed, 13 insertions(+), 12 deletions(-)

diff --git a/include/qemu/lockable.h b/include/qemu/lockable.h
index 2b52c7c1e5..44b3f4be72 100644
--- a/include/qemu/lockable.h
+++ b/include/qemu/lockable.h
@@ -50,6 +50,7 @@ qemu_make_lockable(void *x, QemuLockable *lockable)
 #define QEMU_LOCK_FUNC(x) ((QemuLockUnlockFunc *)    \
     QEMU_GENERIC(x,                                  \
                  (QemuMutex *, qemu_mutex_lock),     \
+                 (QemuRecMutex *, qemu_rec_mutex_lock), \
                  (CoMutex *, qemu_co_mutex_lock),    \
                  (QemuSpin *, qemu_spin_lock),       \
                  unknown_lock_type))
@@ -57,6 +58,7 @@ qemu_make_lockable(void *x, QemuLockable *lockable)
 #define QEMU_UNLOCK_FUNC(x) ((QemuLockUnlockFunc *)  \
     QEMU_GENERIC(x,                                  \
                  (QemuMutex *, qemu_mutex_unlock),   \
+                 (QemuRecMutex *, qemu_rec_mutex_unlock), \
                  (CoMutex *, qemu_co_mutex_unlock),  \
                  (QemuSpin *, qemu_spin_unlock),     \
                  unknown_lock_type))
diff --git a/plugins/core.c b/plugins/core.c
index ed863011ba..51bfc94787 100644
--- a/plugins/core.c
+++ b/plugins/core.c
@@ -15,6 +15,7 @@
 #include "qemu/error-report.h"
 #include "qemu/config-file.h"
 #include "qapi/error.h"
+#include "qemu/lockable.h"
 #include "qemu/option.h"
 #include "qemu/rcu_queue.h"
 #include "qemu/xxhash.h"
@@ -150,11 +151,11 @@ do_plugin_register_cb(qemu_plugin_id_t id, enum qemu_plugin_event ev,
 {
     struct qemu_plugin_ctx *ctx;
 
-    qemu_rec_mutex_lock(&plugin.lock);
+    QEMU_LOCK_GUARD(&plugin.lock);
     ctx = plugin_id_to_ctx_locked(id);
     /* if the plugin is on its way out, ignore this request */
     if (unlikely(ctx->uninstalling)) {
-        goto out_unlock;
+        return;
     }
     if (func) {
         struct qemu_plugin_cb *cb = ctx->callbacks[ev];
@@ -178,8 +179,6 @@ do_plugin_register_cb(qemu_plugin_id_t id, enum qemu_plugin_event ev,
     } else {
         plugin_unregister_cb__locked(ctx, ev);
     }
- out_unlock:
-    qemu_rec_mutex_unlock(&plugin.lock);
 }
 
 void plugin_register_cb(qemu_plugin_id_t id, enum qemu_plugin_event ev,
diff --git a/plugins/loader.c b/plugins/loader.c
index 15fc7e5515..685d334e1a 100644
--- a/plugins/loader.c
+++ b/plugins/loader.c
@@ -19,6 +19,7 @@
 #include "qemu/error-report.h"
 #include "qemu/config-file.h"
 #include "qapi/error.h"
+#include "qemu/lockable.h"
 #include "qemu/option.h"
 #include "qemu/rcu_queue.h"
 #include "qemu/qht.h"
@@ -367,15 +368,14 @@ void plugin_reset_uninstall(qemu_plugin_id_t id,
     struct qemu_plugin_reset_data *data;
     struct qemu_plugin_ctx *ctx;
 
-    qemu_rec_mutex_lock(&plugin.lock);
-    ctx = plugin_id_to_ctx_locked(id);
-    if (ctx->uninstalling || (reset && ctx->resetting)) {
-        qemu_rec_mutex_unlock(&plugin.lock);
-        return;
+    WITH_QEMU_LOCK_GUARD(&plugin.lock) {
+        ctx = plugin_id_to_ctx_locked(id);
+        if (ctx->uninstalling || (reset && ctx->resetting)) {
+            return;
+        }
+        ctx->resetting = reset;
+        ctx->uninstalling = !reset;
     }
-    ctx->resetting = reset;
-    ctx->uninstalling = !reset;
-    qemu_rec_mutex_unlock(&plugin.lock);
 
     data = g_new(struct qemu_plugin_reset_data, 1);
     data->ctx = ctx;
-- 
2.24.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v2 0/2] thread: add lock guard macros
  2020-03-16 11:09 [PATCH v2 0/2] thread: add lock guard macros Stefan Hajnoczi
  2020-03-16 11:09 ` [PATCH v2 1/2] lockable: add lock guards Stefan Hajnoczi
  2020-03-16 11:09 ` [PATCH v2 2/2] lockable: add QemuRecMutex support Stefan Hajnoczi
@ 2020-03-16 11:29 ` Paolo Bonzini
  2 siblings, 0 replies; 4+ messages in thread
From: Paolo Bonzini @ 2020-03-16 11:29 UTC (permalink / raw)
  To: Stefan Hajnoczi, qemu-devel
  Cc: Alex Bennée, Markus Armbruster, Dr. David Alan Gilbert

On 16/03/20 12:09, Stefan Hajnoczi wrote:
> Lock guards automatically call qemu_(rec_)mutex_unlock() when returning from a
> function or leaving leaving a lexical scope.  This simplifies code and
> eliminates leaks (especially in error code paths).
> 
> This series adds lock guards for QemuMutex and QemuRecMutex.  It does not
> convert the entire tree but includes example conversions.
> 
> Stefan Hajnoczi (2):
>   lockable: add lock guards
>   lockable: add QemuRecMutex support
> 
>  include/qemu/lockable.h | 67 +++++++++++++++++++++++++++++++++++++++++
>  plugins/core.c          |  7 ++---
>  plugins/loader.c        | 16 +++++-----
>  util/qemu-timer.c       | 23 +++++++-------
>  4 files changed, 89 insertions(+), 24 deletions(-)
> 

Queued, thanks.

Paolo



^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2020-03-16 12:02 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-16 11:09 [PATCH v2 0/2] thread: add lock guard macros Stefan Hajnoczi
2020-03-16 11:09 ` [PATCH v2 1/2] lockable: add lock guards Stefan Hajnoczi
2020-03-16 11:09 ` [PATCH v2 2/2] lockable: add QemuRecMutex support Stefan Hajnoczi
2020-03-16 11:29 ` [PATCH v2 0/2] thread: add lock guard macros Paolo Bonzini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.