[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PULL 43/45] include/qemu/lockable: Use _Generic instead of QEMU_GENERIC
From: |
Paolo Bonzini |
Subject: |
[PULL 43/45] include/qemu/lockable: Use _Generic instead of QEMU_GENERIC |
Date: |
Thu, 17 Jun 2021 11:31:32 +0200 |
From: Richard Henderson <richard.henderson@linaro.org>
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>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Tested-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20210614233143.1221879-7-richard.henderson@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
include/qemu/lockable.h | 90 +++++++++++++++++++----------------------
1 file changed, 41 insertions(+), 49 deletions(-)
diff --git a/include/qemu/lockable.h b/include/qemu/lockable.h
index b620023141..86db7cb04c 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))
+static inline __attribute__((__always_inline__)) QemuLockable *
+qemu_null_lockable(void *x)
+{
+ if (x != NULL) {
+ qemu_build_not_reached();
+ }
+ return NULL;
+}
-#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.
+/*
+ * 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.
- */
-#define QEMU_MAKE_LOCKABLE(x) \
- QEMU_GENERIC(x, \
- (QemuLockable *, (x)), \
- qemu_make_lockable((x), QEMU_MAKE_LOCKABLE_(x)))
-
-/* QEMU_MAKE_LOCKABLE_NONNULL - Make a polymorphic QemuLockable
*
- * @x: a lock object (currently one of QemuMutex, QemuRecMutex, CoMutex,
QemuSpin).
+ * Note the special case for void *, so that we may pass "NULL".
+ */
+#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
+ *
+ * @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)
{
--
2.31.1
- [PULL 26/45] util/mmap-alloc: Support RAM_NORESERVE via MAP_NORESERVE under Linux, (continued)
- [PULL 26/45] util/mmap-alloc: Support RAM_NORESERVE via MAP_NORESERVE under Linux, Paolo Bonzini, 2021/06/17
- [PULL 23/45] softmmu/memory: Pass ram_flags to qemu_ram_alloc() and qemu_ram_alloc_internal(), Paolo Bonzini, 2021/06/17
- [PULL 29/45] qmp: Include "share" property of memory backends, Paolo Bonzini, 2021/06/17
- [PULL 33/45] configure: map x32 to cpu_family x86_64 for meson, Paolo Bonzini, 2021/06/17
- [PULL 36/45] target/i386: Added consistency checks for CR0, Paolo Bonzini, 2021/06/17
- [PULL 38/45] configure: Use -std=gnu11, Paolo Bonzini, 2021/06/17
- [PULL 40/45] util: Use real functions for thread-posix QemuRecMutex, Paolo Bonzini, 2021/06/17
- [PULL 42/45] util: Use unique type for QemuRecMutex in thread-posix.h, Paolo Bonzini, 2021/06/17
- [PULL 37/45] target/i386: Added Intercept CR0 writes check, Paolo Bonzini, 2021/06/17
- [PULL 44/45] qemu/compiler: Remove QEMU_GENERIC, Paolo Bonzini, 2021/06/17
- [PULL 43/45] include/qemu/lockable: Use _Generic instead of QEMU_GENERIC,
Paolo Bonzini <=
- [PULL 21/45] softmmu/memory: Pass ram_flags to qemu_ram_alloc_from_fd(), Paolo Bonzini, 2021/06/17
- [PULL 25/45] memory: Introduce RAM_NORESERVE and wire it up in qemu_ram_mmap(), Paolo Bonzini, 2021/06/17
- [PULL 24/45] util/mmap-alloc: Pass flags instead of separate bools to qemu_ram_mmap(), Paolo Bonzini, 2021/06/17
- [PULL 27/45] hostmem: Wire up RAM_NORESERVE via "reserve" property, Paolo Bonzini, 2021/06/17
- [PULL 28/45] qmp: Clarify memory backend properties returned via query-memdev, Paolo Bonzini, 2021/06/17
- [PULL 30/45] hmp: Print "share" property of memory backends with "info memdev", Paolo Bonzini, 2021/06/17
- [PULL 35/45] target/i386: Added consistency checks for VMRUN intercept and ASID, Paolo Bonzini, 2021/06/17
- [PULL 34/45] target/i386: Refactored intercept checks into cpu_svm_has_intercept, Paolo Bonzini, 2021/06/17
- [PULL 39/45] softfloat: Use _Generic instead of QEMU_GENERIC, Paolo Bonzini, 2021/06/17
- [PULL 41/45] util: Pass file+line to qemu_rec_mutex_unlock_impl, Paolo Bonzini, 2021/06/17