]> git.proxmox.com Git - mirror_qemu.git/blob - include/qemu/lockable.h
Merge tag 'pull-riscv-to-apply-20240110' of https://github.com/alistair23/qemu into...
[mirror_qemu.git] / include / qemu / lockable.h
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-core.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 static inline __attribute__((__always_inline__)) QemuLockable *
28 qemu_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
37 static inline __attribute__((__always_inline__)) QemuLockable *
38 qemu_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
93 static inline void qemu_lockable_lock(QemuLockable *x)
94 {
95 x->lock(x->object);
96 }
97
98 static inline void qemu_lockable_unlock(QemuLockable *x)
99 {
100 x->unlock(x->object);
101 }
102
103 static inline QemuLockable *qemu_lockable_auto_lock(QemuLockable *x)
104 {
105 qemu_lockable_lock(x);
106 return x;
107 }
108
109 static inline void qemu_lockable_auto_unlock(QemuLockable *x)
110 {
111 if (x) {
112 qemu_lockable_unlock(x);
113 }
114 }
115
116 G_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