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