[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 2/5] lock-guard: add scoped lock implementation
From: |
Paolo Bonzini |
Subject: |
[Qemu-devel] [PATCH 2/5] lock-guard: add scoped lock implementation |
Date: |
Fri, 8 Dec 2017 11:55:50 +0100 |
Signed-off-by: Paolo Bonzini <address@hidden>
---
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 <address@hidden>
+ *
+ * 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
- [Qemu-devel] [RFC PATCH 0/5] Scoped locks using attribute((cleanup)), Paolo Bonzini, 2017/12/08
- [Qemu-devel] [PATCH 1/5] compiler: add a helper for C99 inline functions, Paolo Bonzini, 2017/12/08
- [Qemu-devel] [PATCH 2/5] lock-guard: add scoped lock implementation,
Paolo Bonzini <=
- Re: [Qemu-devel] [PATCH 2/5] lock-guard: add scoped lock implementation, Stefan Hajnoczi, 2017/12/08
- Re: [Qemu-devel] [PATCH 2/5] lock-guard: add scoped lock implementation, Paolo Bonzini, 2017/12/08
- Re: [Qemu-devel] [PATCH 2/5] lock-guard: add scoped lock implementation, Eric Blake, 2017/12/08
- Re: [Qemu-devel] [PATCH 2/5] lock-guard: add scoped lock implementation, Stefan Hajnoczi, 2017/12/11
- Re: [Qemu-devel] [PATCH 2/5] lock-guard: add scoped lock implementation, Eric Blake, 2017/12/11
- Re: [Qemu-devel] [PATCH 2/5] lock-guard: add scoped lock implementation, Stefan Hajnoczi, 2017/12/12
[Qemu-devel] [PATCH 3/5] qemu-timer: convert to use lock guards, Paolo Bonzini, 2017/12/08
[Qemu-devel] [PATCH 4/5] qht: convert to use lock guards, Paolo Bonzini, 2017/12/08