lockable.h (5224B)
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 19typedef void QemuLockUnlockFunc(void *); 20 21struct QemuLockable { 22 void *object; 23 QemuLockUnlockFunc *lock; 24 QemuLockUnlockFunc *unlock; 25}; 26 27static inline __attribute__((__always_inline__)) QemuLockable * 28qemu_make_lockable(void *x, QemuLockable *lockable) 29{ 30 /* 31 * We cannot test this in a macro, otherwise we get compiler 32 * warnings like "the address of 'm' will always evaluate as 'true'". 33 */ 34 return x ? lockable : NULL; 35} 36 37static inline __attribute__((__always_inline__)) QemuLockable * 38qemu_null_lockable(void *x) 39{ 40 if (x != NULL) { 41 qemu_build_not_reached(); 42 } 43 return NULL; 44} 45 46/* 47 * In C, compound literals have the lifetime of an automatic variable. 48 * In C++ it would be different, but then C++ wouldn't need QemuLockable 49 * either... 50 */ 51#define QML_OBJ_(x, name) (&(QemuLockable) { \ 52 .object = (x), \ 53 .lock = (QemuLockUnlockFunc *) qemu_ ## name ## _lock, \ 54 .unlock = (QemuLockUnlockFunc *) qemu_ ## name ## _unlock \ 55 }) 56 57/** 58 * QEMU_MAKE_LOCKABLE - Make a polymorphic QemuLockable 59 * 60 * @x: a lock object (currently one of QemuMutex, QemuRecMutex, 61 * CoMutex, QemuSpin). 62 * 63 * Returns a QemuLockable object that can be passed around 64 * to a function that can operate with locks of any kind, or 65 * NULL if @x is %NULL. 66 * 67 * Note the special case for void *, so that we may pass "NULL". 68 */ 69#define QEMU_MAKE_LOCKABLE(x) \ 70 _Generic((x), QemuLockable *: (x), \ 71 void *: qemu_null_lockable(x), \ 72 QemuMutex *: qemu_make_lockable(x, QML_OBJ_(x, mutex)), \ 73 QemuRecMutex *: qemu_make_lockable(x, QML_OBJ_(x, rec_mutex)), \ 74 CoMutex *: qemu_make_lockable(x, QML_OBJ_(x, co_mutex)), \ 75 QemuSpin *: qemu_make_lockable(x, QML_OBJ_(x, spin))) 76 77/** 78 * QEMU_MAKE_LOCKABLE_NONNULL - Make a polymorphic QemuLockable 79 * 80 * @x: a lock object (currently one of QemuMutex, QemuRecMutex, 81 * CoMutex, QemuSpin). 82 * 83 * Returns a QemuLockable object that can be passed around 84 * to a function that can operate with locks of any kind. 85 */ 86#define QEMU_MAKE_LOCKABLE_NONNULL(x) \ 87 _Generic((x), QemuLockable *: (x), \ 88 QemuMutex *: QML_OBJ_(x, mutex), \ 89 QemuRecMutex *: QML_OBJ_(x, rec_mutex), \ 90 CoMutex *: QML_OBJ_(x, co_mutex), \ 91 QemuSpin *: QML_OBJ_(x, spin)) 92 93static inline void qemu_lockable_lock(QemuLockable *x) 94{ 95 x->lock(x->object); 96} 97 98static inline void qemu_lockable_unlock(QemuLockable *x) 99{ 100 x->unlock(x->object); 101} 102 103static inline QemuLockable *qemu_lockable_auto_lock(QemuLockable *x) 104{ 105 qemu_lockable_lock(x); 106 return x; 107} 108 109static inline void qemu_lockable_auto_unlock(QemuLockable *x) 110{ 111 if (x) { 112 qemu_lockable_unlock(x); 113 } 114} 115 116G_DEFINE_AUTOPTR_CLEANUP_FUNC(QemuLockable, qemu_lockable_auto_unlock) 117 118#define WITH_QEMU_LOCK_GUARD_(x, var) \ 119 for (g_autoptr(QemuLockable) var = \ 120 qemu_lockable_auto_lock(QEMU_MAKE_LOCKABLE_NONNULL((x))); \ 121 var; \ 122 qemu_lockable_auto_unlock(var), var = NULL) 123 124/** 125 * WITH_QEMU_LOCK_GUARD - Lock a lock object for scope 126 * 127 * @x: a lock object (currently one of QemuMutex, CoMutex, QemuSpin). 128 * 129 * This macro defines a lock scope such that entering the scope takes the lock 130 * and leaving the scope releases the lock. Return statements are allowed 131 * within the scope and release the lock. Break and continue statements leave 132 * the scope early and release the lock. 133 * 134 * WITH_QEMU_LOCK_GUARD(&mutex) { 135 * ... 136 * if (error) { 137 * return; <-- mutex is automatically unlocked 138 * } 139 * 140 * if (early_exit) { 141 * break; <-- leave this scope early 142 * } 143 * ... 144 * } 145 */ 146#define WITH_QEMU_LOCK_GUARD(x) \ 147 WITH_QEMU_LOCK_GUARD_((x), glue(qemu_lockable_auto, __COUNTER__)) 148 149/** 150 * QEMU_LOCK_GUARD - Lock an object until the end of the scope 151 * 152 * @x: a lock object (currently one of QemuMutex, CoMutex, QemuSpin). 153 * 154 * This macro takes a lock until the end of the scope. Return statements 155 * release the lock. 156 * 157 * ... <-- mutex not locked 158 * QEMU_LOCK_GUARD(&mutex); <-- mutex locked from here onwards 159 * ... 160 * if (error) { 161 * return; <-- mutex is automatically unlocked 162 * } 163 */ 164#define QEMU_LOCK_GUARD(x) \ 165 g_autoptr(QemuLockable) \ 166 glue(qemu_lockable_auto, __COUNTER__) G_GNUC_UNUSED = \ 167 qemu_lockable_auto_lock(QEMU_MAKE_LOCKABLE((x))) 168 169#endif