1 /* 2 * Polymorphic locking functions (aka poor man templates) 3 * 4 * Copyright Red Hat, Inc. 2017, 2018 5 * 6 * Author: Paolo Bonzini <pbonzini@redhat.com> 7 * 8 * This work is licensed under the terms of the GNU LGPL, version 2 or later. 9 * See the COPYING.LIB file in the top-level directory. 10 * 11 */ 12 13 #ifndef QEMU_LOCKABLE_H 14 #define QEMU_LOCKABLE_H 15 16 #include "qemu/coroutine.h" 17 #include "qemu/thread.h" 18 19 typedef void QemuLockUnlockFunc(void *); 20 21 struct QemuLockable { 22 void *object; 23 QemuLockUnlockFunc *lock; 24 QemuLockUnlockFunc *unlock; 25 }; 26 27 /* This function gives an error if an invalid, non-NULL pointer type is passed 28 * to QEMU_MAKE_LOCKABLE. For optimized builds, we can rely on dead-code elimination 29 * from the compiler, and give the errors already at link time. 30 */ 31 #ifdef __OPTIMIZE__ 32 void unknown_lock_type(void *); 33 #else 34 static inline void unknown_lock_type(void *unused) 35 { 36 abort(); 37 } 38 #endif 39 40 static inline __attribute__((__always_inline__)) QemuLockable * 41 qemu_make_lockable(void *x, QemuLockable *lockable) 42 { 43 /* We cannot test this in a macro, otherwise we get compiler 44 * warnings like "the address of 'm' will always evaluate as 'true'". 45 */ 46 return x ? lockable : NULL; 47 } 48 49 /* Auxiliary macros to simplify QEMU_MAKE_LOCABLE. */ 50 #define QEMU_LOCK_FUNC(x) ((QemuLockUnlockFunc *) \ 51 QEMU_GENERIC(x, \ 52 (QemuMutex *, qemu_mutex_lock), \ 53 (CoMutex *, qemu_co_mutex_lock), \ 54 (QemuSpin *, qemu_spin_lock), \ 55 unknown_lock_type)) 56 57 #define QEMU_UNLOCK_FUNC(x) ((QemuLockUnlockFunc *) \ 58 QEMU_GENERIC(x, \ 59 (QemuMutex *, qemu_mutex_unlock), \ 60 (CoMutex *, qemu_co_mutex_unlock), \ 61 (QemuSpin *, qemu_spin_unlock), \ 62 unknown_lock_type)) 63 64 /* In C, compound literals have the lifetime of an automatic variable. 65 * In C++ it would be different, but then C++ wouldn't need QemuLockable 66 * either... 67 */ 68 #define QEMU_MAKE_LOCKABLE_(x) qemu_make_lockable((x), &(QemuLockable) { \ 69 .object = (x), \ 70 .lock = QEMU_LOCK_FUNC(x), \ 71 .unlock = QEMU_UNLOCK_FUNC(x), \ 72 }) 73 74 /* QEMU_MAKE_LOCKABLE - Make a polymorphic QemuLockable 75 * 76 * @x: a lock object (currently one of QemuMutex, CoMutex, QemuSpin). 77 * 78 * Returns a QemuLockable object that can be passed around 79 * to a function that can operate with locks of any kind. 80 */ 81 #define QEMU_MAKE_LOCKABLE(x) \ 82 QEMU_GENERIC(x, \ 83 (QemuLockable *, (x)), \ 84 QEMU_MAKE_LOCKABLE_(x)) 85 86 static inline void qemu_lockable_lock(QemuLockable *x) 87 { 88 x->lock(x->object); 89 } 90 91 static inline void qemu_lockable_unlock(QemuLockable *x) 92 { 93 x->unlock(x->object); 94 } 95 96 #endif 97