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
next prev 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).