2 * Polymorphic locking functions (aka poor man templates)
4 * Copyright Red Hat, Inc. 2017, 2018
6 * Author: Paolo Bonzini <pbonzini@redhat.com>
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.
13 #ifndef QEMU_LOCKABLE_H
14 #define QEMU_LOCKABLE_H
16 #include "qemu/coroutine-core.h"
17 #include "qemu/thread.h"
19 typedef void QemuLockUnlockFunc(void *);
23 QemuLockUnlockFunc
*lock
;
24 QemuLockUnlockFunc
*unlock
;
27 static inline __attribute__((__always_inline__
)) QemuLockable
*
28 qemu_make_lockable(void *x
, QemuLockable
*lockable
)
31 * We cannot test this in a macro, otherwise we get compiler
32 * warnings like "the address of 'm' will always evaluate as 'true'".
34 return x
? lockable
: NULL
;
37 static inline __attribute__((__always_inline__
)) QemuLockable
*
38 qemu_null_lockable(void *x
)
41 qemu_build_not_reached();
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
51 #define QML_OBJ_(x, name) (&(QemuLockable) { \
53 .lock = (QemuLockUnlockFunc *) qemu_ ## name ## _lock, \
54 .unlock = (QemuLockUnlockFunc *) qemu_ ## name ## _unlock \
58 * QEMU_MAKE_LOCKABLE - Make a polymorphic QemuLockable
60 * @x: a lock object (currently one of QemuMutex, QemuRecMutex,
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.
67 * Note the special case for void *, so that we may pass "NULL".
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)))
78 * QEMU_MAKE_LOCKABLE_NONNULL - Make a polymorphic QemuLockable
80 * @x: a lock object (currently one of QemuMutex, QemuRecMutex,
83 * Returns a QemuLockable object that can be passed around
84 * to a function that can operate with locks of any kind.
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))
93 static inline void qemu_lockable_lock(QemuLockable
*x
)
98 static inline void qemu_lockable_unlock(QemuLockable
*x
)
100 x
->unlock(x
->object
);
103 static inline QemuLockable
*qemu_lockable_auto_lock(QemuLockable
*x
)
105 qemu_lockable_lock(x
);
109 static inline void qemu_lockable_auto_unlock(QemuLockable
*x
)
112 qemu_lockable_unlock(x
);
116 G_DEFINE_AUTOPTR_CLEANUP_FUNC(QemuLockable
, qemu_lockable_auto_unlock
)
118 #define WITH_QEMU_LOCK_GUARD_(x, var) \
119 for (g_autoptr(QemuLockable) var = \
120 qemu_lockable_auto_lock(QEMU_MAKE_LOCKABLE_NONNULL((x))); \
122 qemu_lockable_auto_unlock(var), var = NULL)
125 * WITH_QEMU_LOCK_GUARD - Lock a lock object for scope
127 * @x: a lock object (currently one of QemuMutex, CoMutex, QemuSpin).
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.
134 * WITH_QEMU_LOCK_GUARD(&mutex) {
137 * return; <-- mutex is automatically unlocked
141 * break; <-- leave this scope early
146 #define WITH_QEMU_LOCK_GUARD(x) \
147 WITH_QEMU_LOCK_GUARD_((x), glue(qemu_lockable_auto, __COUNTER__))
150 * QEMU_LOCK_GUARD - Lock an object until the end of the scope
152 * @x: a lock object (currently one of QemuMutex, CoMutex, QemuSpin).
154 * This macro takes a lock until the end of the scope. Return statements
157 * ... <-- mutex not locked
158 * QEMU_LOCK_GUARD(&mutex); <-- mutex locked from here onwards
161 * return; <-- mutex is automatically unlocked
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)))