qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Paolo Bonzini <pbonzini@redhat.com>
To: qemu-devel@nongnu.org
Cc: "Emilio G . Cota" <cota@braap.org>,
	Stefan Hajnoczi <stefanha@redhat.com>,
	Fam Zheng <famz@redhat.com>
Subject: [Qemu-devel] [PATCH 2/5] lock-guard: add scoped lock implementation
Date: Fri,  8 Dec 2017 11:55:50 +0100	[thread overview]
Message-ID: <20171208105553.12249-3-pbonzini@redhat.com> (raw)
In-Reply-To: <20171208105553.12249-1-pbonzini@redhat.com>

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 include/qemu/coroutine.h  |  4 ++
 include/qemu/lock-guard.h | 99 +++++++++++++++++++++++++++++++++++++++++++++++
 include/qemu/thread.h     |  7 ++++
 util/Makefile.objs        |  1 +
 util/qemu-thread.c        | 17 ++++++++
 5 files changed, 128 insertions(+)
 create mode 100644 include/qemu/lock-guard.h
 create mode 100644 util/qemu-thread.c

diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h
index 9aff9a735e..8b48803fa8 100644
--- a/include/qemu/coroutine.h
+++ b/include/qemu/coroutine.h
@@ -17,6 +17,7 @@
 
 #include "qemu/queue.h"
 #include "qemu/timer.h"
+#include "qemu/lock-guard.h"
 
 /**
  * Coroutines are a mechanism for stack switching and can be used for
@@ -162,6 +163,9 @@ void coroutine_fn qemu_co_mutex_lock(CoMutex *mutex);
  */
 void coroutine_fn qemu_co_mutex_unlock(CoMutex *mutex);
 
+#define QEMU_LOCK_GUARD_FUNCS_CoMutex \
+    QEMU_INIT_LOCK_GUARD(CoMutex, qemu_co_mutex_lock, qemu_co_mutex_unlock)
+
 
 /**
  * CoQueues are a mechanism to queue coroutines in order to continue executing
diff --git a/include/qemu/lock-guard.h b/include/qemu/lock-guard.h
new file mode 100644
index 0000000000..e6a83bf9ee
--- /dev/null
+++ b/include/qemu/lock-guard.h
@@ -0,0 +1,103 @@
+#ifndef QEMU_LOCK_GUARD_H
+#define QEMU_LOCK_GUARD_H 1
+
+typedef void QemuLockGuardFunc(void *);
+typedef struct QemuLockGuard {
+    QemuLockGuardFunc *p_lock_fn, *p_unlock_fn;
+    void *lock;
+    int locked;
+} QemuLockGuard;
+
+static inline void qemu_lock_guard_lock(QemuLockGuard *lock_guard)
+{
+    assert(!lock_guard->locked);
+    lock_guard->p_lock_fn(lock_guard->lock);
+    lock_guard->locked = true;
+}
+
+static inline void qemu_lock_guard_unlock(QemuLockGuard *lock_guard)
+{
+    assert(lock_guard->locked);
+    lock_guard->locked = false;
+    lock_guard->p_unlock_fn(lock_guard->lock);
+}
+
+static inline bool qemu_lock_guard_is_taken(QemuLockGuard *lock_guard)
+{
+    return lock_guard->locked;
+}
+
+static inline void qemu_lock_guard_release(QemuLockGuard *lock_guard)
+{
+    lock_guard->lock = NULL;
+    lock_guard->locked = false;
+}
+
+inline void qemu_lock_guard_pass(void *ptr)
+{
+    QemuLockGuard *lock_guard = ptr;
+    assert(lock_guard->locked || !lock_guard->lock);
+}
+
+inline void qemu_lock_guard_cleanup(void *ptr)
+{
+    QemuLockGuard *lock_guard = ptr;
+    if (likely(lock_guard->locked)) {
+        lock_guard->p_unlock_fn(lock_guard->lock);
+    }
+}
+
+static inline QemuLockGuard qemu_lock_guard_init(QemuLockGuard lock_guard)
+{
+    qemu_lock_guard_lock(&lock_guard);
+    return lock_guard;
+}
+
+#define QEMU_INIT_LOCK_GUARD(type, lock_fn, unlock_fn)                     \
+    .p_lock_fn   = (QemuLockGuardFunc *) (void (*) (type *)) lock_fn,      \
+    .p_unlock_fn = (QemuLockGuardFunc *) (void (*) (type *)) unlock_fn
+
+#define QEMU_LOCK_GUARD_(type, lock, locked)                               \
+    (QemuLockGuard) {                                                      \
+        QEMU_LOCK_GUARD_FUNCS_##type,                                      \
+        lock + type_check(typeof(*lock), type),                            \
+        locked                                                             \
+    }
+
+/* Take a lock that will be unlocked on returning */
+#define QEMU_LOCK_GUARD(type, name, lock)                                  \
+    QemuLockGuard __attribute__((cleanup(qemu_lock_guard_cleanup))) name = \
+        qemu_lock_guard_init(QEMU_LOCK_GUARD_(type, lock, false))
+
+#define QEMU_WITH_LOCK(type, name, lock)                                   \
+    for (QEMU_LOCK_GUARD(type, name, lock);                                \
+         qemu_lock_guard_is_taken(&name);                                  \
+         qemu_lock_guard_unlock(&name))
+
+/* Create a QemuLockGuard for a lock that is taken and will be unlocked on
+ * returning
+ */
+#define QEMU_ADOPT_LOCK(type, name, lock)                                  \
+    QemuLockGuard __attribute__((cleanup(qemu_lock_guard_cleanup))) name = \
+        QEMU_LOCK_GUARD_(type, lock, true)
+
+#define QEMU_WITH_ADOPTED_LOCK(type, name, lock)                           \
+    for (QEMU_ADOPT_LOCK(type, name, lock);                                \
+         qemu_lock_guard_is_taken(&name);                                  \
+         qemu_lock_guard_unlock(&name))
+
+/* Take a lock and create a QemuLockGuard for it, asserting that it will
+ * be locked when returning.
+ */
+#define QEMU_RETURN_LOCK(type, name, lock)                                 \
+    QemuLockGuard __attribute__((cleanup(qemu_lock_guard_pass))) name =    \
+        qemu_lock_guard_init(QEMU_LOCK_GUARD_(type, lock, false))
+
+/* Create a QemuLockGuard for a lock that is taken and must be locked
+ * when returning
+ */
+#define QEMU_TAKEN_LOCK(type, name, lock)                                  \
+    QemuLockGuard __attribute__((cleanup(qemu_lock_guard_pass))) name =    \
+        QEMU_LOCK_GUARD_(type, lock, true)
+
+#endif
diff --git a/include/qemu/thread.h b/include/qemu/thread.h
index 9910f49b3a..4066702d0c 100644
--- a/include/qemu/thread.h
+++ b/include/qemu/thread.h
@@ -3,6 +3,7 @@
 
 #include "qemu/processor.h"
 #include "qemu/atomic.h"
+#include "qemu/lock-guard.h"
 
 typedef struct QemuMutex QemuMutex;
 typedef struct QemuCond QemuCond;
@@ -26,6 +27,9 @@ void qemu_mutex_lock(QemuMutex *mutex);
 int qemu_mutex_trylock(QemuMutex *mutex);
 void qemu_mutex_unlock(QemuMutex *mutex);
 
+#define QEMU_LOCK_GUARD_FUNCS_QemuMutex \
+    QEMU_INIT_LOCK_GUARD(QemuMutex, qemu_mutex_lock, qemu_mutex_unlock)
+
 /* Prototypes for other functions are in thread-posix.h/thread-win32.h.  */
 void qemu_rec_mutex_init(QemuRecMutex *mutex);
 
@@ -99,6 +103,9 @@ static inline void qemu_spin_unlock(QemuSpin *spin)
     __sync_lock_release(&spin->value);
 }
 
+#define QEMU_LOCK_GUARD_FUNCS_QemuSpin \
+    QEMU_INIT_LOCK_GUARD(QemuSpin, qemu_spin_lock, qemu_spin_lock)
+
 struct QemuLockCnt {
 #ifndef CONFIG_LINUX
     QemuMutex mutex;
diff --git a/util/Makefile.objs b/util/Makefile.objs
index 2973b0a323..cb0591f750 100644
--- a/util/Makefile.objs
+++ b/util/Makefile.objs
@@ -3,6 +3,7 @@ util-obj-y += bufferiszero.o
 util-obj-y += lockcnt.o
 util-obj-y += aiocb.o async.o thread-pool.o qemu-timer.o
 util-obj-y += main-loop.o iohandler.o
+util-obj-y += qemu-thread.o
 util-obj-$(CONFIG_POSIX) += aio-posix.o
 util-obj-$(CONFIG_POSIX) += compatfd.o
 util-obj-$(CONFIG_POSIX) += event_notifier-posix.o
diff --git a/util/qemu-thread.c b/util/qemu-thread.c
new file mode 100644
index 0000000000..bb06b5f58b
--- /dev/null
+++ b/util/qemu-thread.c
@@ -0,0 +1,17 @@
+/*
+ * Extern inline functions for QemuLockGuard.
+ *
+ * Copyright Red Hat, Inc. 2017
+ *
+ * Author:
+ *  Paolo Bonzini <pbonzini@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+#include "qemu/osdep.h"
+#include "qemu/thread.h"
+
+QEMU_EXTERN_INLINE(qemu_lock_guard_cleanup)
+QEMU_EXTERN_INLINE(qemu_lock_guard_pass)
-- 
2.14.3

  parent reply	other threads:[~2017-12-08 10:56 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-12-08 10:55 [Qemu-devel] [RFC PATCH 0/5] Scoped locks using attribute((cleanup)) Paolo Bonzini
2017-12-08 10:55 ` [Qemu-devel] [PATCH 1/5] compiler: add a helper for C99 inline functions Paolo Bonzini
2017-12-08 10:55 ` Paolo Bonzini [this message]
2017-12-08 15:30   ` [Qemu-devel] [PATCH 2/5] lock-guard: add scoped lock implementation Stefan Hajnoczi
2017-12-08 17:56     ` Paolo Bonzini
2017-12-08 20:12       ` Eric Blake
2017-12-11 10:16       ` Stefan Hajnoczi
2017-12-11 13:51         ` Eric Blake
2017-12-12  9:16           ` Stefan Hajnoczi
2017-12-08 10:55 ` [Qemu-devel] [PATCH 3/5] qemu-timer: convert to use lock guards Paolo Bonzini
2017-12-08 14:26   ` Stefan Hajnoczi
2017-12-08 10:55 ` [Qemu-devel] [PATCH 4/5] qht: " Paolo Bonzini
2017-12-08 14:27   ` Stefan Hajnoczi
2017-12-08 10:55 ` [Qemu-devel] [PATCH 5/5] thread-pool: " Paolo Bonzini
2017-12-08 15:13   ` Stefan Hajnoczi
2017-12-08 18:12     ` Paolo Bonzini
2017-12-08 20:02       ` Eric Blake
2017-12-11 10:23         ` Stefan Hajnoczi
2017-12-11 22:03           ` Paolo Bonzini
2017-12-08 19:50     ` Eric Blake
2017-12-11  6:35     ` Peter Xu
2017-12-08 19:40 ` [Qemu-devel] [RFC PATCH 0/5] Scoped locks using attribute((cleanup)) Eric Blake
2017-12-11  9:38   ` Peter Maydell
2017-12-11 14:11     ` Eric Blake
2017-12-11 21:32       ` Paolo Bonzini
2017-12-12 20:41         ` Eric Blake
2017-12-15 15:50           ` Richard Henderson
2017-12-11  6:40 ` no-reply
2017-12-11  6:40 ` no-reply
2017-12-11  6:46 ` no-reply
2017-12-11 22:06 ` Emilio G. Cota

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20171208105553.12249-3-pbonzini@redhat.com \
    --to=pbonzini@redhat.com \
    --cc=cota@braap.org \
    --cc=famz@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).