aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2021-06-14 16:31:41 -0700
committerRichard Henderson <richard.henderson@linaro.org>2021-06-15 18:31:00 -0700
commit4ffb0681d7de34a5286f390a19fb48709107903b (patch)
treea60d4685aa2637b4018399e52df2641706e22c04 /include
parent6c98635ed7772e63b98944ab972c1eef8e498da3 (diff)
downloadqemu-4ffb0681d7de34a5286f390a19fb48709107903b.zip
qemu-4ffb0681d7de34a5286f390a19fb48709107903b.tar.gz
qemu-4ffb0681d7de34a5286f390a19fb48709107903b.tar.bz2
include/qemu/lockable: Use _Generic instead of QEMU_GENERIC
This is both more and less complicated than our expansion using __builtin_choose_expr and __builtin_types_compatible_p. The expansion through QEMU_MAKE_LOCKABLE_ doesn't work because we're not emumerating all of the types within the same _Generic, which results in errors about unhandled cases. We must also handle void* explicitly, so that the NULL constant can be used. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Tested-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Message-Id: <20210614233143.1221879-7-richard.henderson@linaro.org>
Diffstat (limited to 'include')
-rw-r--r--include/qemu/lockable.h88
1 files changed, 40 insertions, 48 deletions
diff --git a/include/qemu/lockable.h b/include/qemu/lockable.h
index b620023..86db7cb 100644
--- a/include/qemu/lockable.h
+++ b/include/qemu/lockable.h
@@ -24,79 +24,71 @@ struct QemuLockable {
QemuLockUnlockFunc *unlock;
};
-/* This function gives an error if an invalid, non-NULL pointer type is passed
- * to QEMU_MAKE_LOCKABLE. For optimized builds, we can rely on dead-code elimination
- * from the compiler, and give the errors already at link time.
- */
-#if defined(__OPTIMIZE__) && !defined(__SANITIZE_ADDRESS__)
-void unknown_lock_type(void *);
-#else
-static inline void unknown_lock_type(void *unused)
-{
- abort();
-}
-#endif
-
static inline __attribute__((__always_inline__)) QemuLockable *
qemu_make_lockable(void *x, QemuLockable *lockable)
{
- /* We cannot test this in a macro, otherwise we get compiler
+ /*
+ * We cannot test this in a macro, otherwise we get compiler
* warnings like "the address of 'm' will always evaluate as 'true'".
*/
return x ? lockable : NULL;
}
-/* Auxiliary macros to simplify QEMU_MAKE_LOCABLE. */
-#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))
-
-#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))
-
-/* In C, compound literals have the lifetime of an automatic variable.
+static inline __attribute__((__always_inline__)) QemuLockable *
+qemu_null_lockable(void *x)
+{
+ if (x != NULL) {
+ qemu_build_not_reached();
+ }
+ return NULL;
+}
+
+/*
+ * In C, compound literals have the lifetime of an automatic variable.
* In C++ it would be different, but then C++ wouldn't need QemuLockable
* either...
*/
-#define QEMU_MAKE_LOCKABLE_(x) (&(QemuLockable) { \
- .object = (x), \
- .lock = QEMU_LOCK_FUNC(x), \
- .unlock = QEMU_UNLOCK_FUNC(x), \
+#define QML_OBJ_(x, name) (&(QemuLockable) { \
+ .object = (x), \
+ .lock = (QemuLockUnlockFunc *) qemu_ ## name ## _lock, \
+ .unlock = (QemuLockUnlockFunc *) qemu_ ## name ## _unlock \
})
-/* QEMU_MAKE_LOCKABLE - Make a polymorphic QemuLockable
+/**
+ * QEMU_MAKE_LOCKABLE - Make a polymorphic QemuLockable
*
- * @x: a lock object (currently one of QemuMutex, QemuRecMutex, CoMutex, QemuSpin).
+ * @x: a lock object (currently one of QemuMutex, QemuRecMutex,
+ * CoMutex, QemuSpin).
*
* Returns a QemuLockable object that can be passed around
* to a function that can operate with locks of any kind, or
* NULL if @x is %NULL.
+ *
+ * Note the special case for void *, so that we may pass "NULL".
*/
-#define QEMU_MAKE_LOCKABLE(x) \
- QEMU_GENERIC(x, \
- (QemuLockable *, (x)), \
- qemu_make_lockable((x), QEMU_MAKE_LOCKABLE_(x)))
+#define QEMU_MAKE_LOCKABLE(x) \
+ _Generic((x), QemuLockable *: (x), \
+ void *: qemu_null_lockable(x), \
+ QemuMutex *: qemu_make_lockable(x, QML_OBJ_(x, mutex)), \
+ QemuRecMutex *: qemu_make_lockable(x, QML_OBJ_(x, rec_mutex)), \
+ CoMutex *: qemu_make_lockable(x, QML_OBJ_(x, co_mutex)), \
+ QemuSpin *: qemu_make_lockable(x, QML_OBJ_(x, spin)))
-/* QEMU_MAKE_LOCKABLE_NONNULL - Make a polymorphic QemuLockable
+/**
+ * QEMU_MAKE_LOCKABLE_NONNULL - Make a polymorphic QemuLockable
*
- * @x: a lock object (currently one of QemuMutex, QemuRecMutex, CoMutex, QemuSpin).
+ * @x: a lock object (currently one of QemuMutex, QemuRecMutex,
+ * CoMutex, QemuSpin).
*
* Returns a QemuLockable object that can be passed around
* to a function that can operate with locks of any kind.
*/
-#define QEMU_MAKE_LOCKABLE_NONNULL(x) \
- QEMU_GENERIC(x, \
- (QemuLockable *, (x)), \
- QEMU_MAKE_LOCKABLE_(x))
+#define QEMU_MAKE_LOCKABLE_NONNULL(x) \
+ _Generic((x), QemuLockable *: (x), \
+ QemuMutex *: QML_OBJ_(x, mutex), \
+ QemuRecMutex *: QML_OBJ_(x, rec_mutex), \
+ CoMutex *: QML_OBJ_(x, co_mutex), \
+ QemuSpin *: QML_OBJ_(x, spin))
static inline void qemu_lockable_lock(QemuLockable *x)
{