]>
Commit | Line | Data |
---|---|---|
e70372fc PB |
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 | */ | |
80818e9e | 31 | #if defined(__OPTIMIZE__) && !defined(__SANITIZE_ADDRESS__) |
e70372fc PB |
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 | */ | |
8834dcf4 | 68 | #define QEMU_MAKE_LOCKABLE_(x) (&(QemuLockable) { \ |
e70372fc PB |
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 | |
8834dcf4 PB |
79 | * to a function that can operate with locks of any kind, or |
80 | * NULL if @x is %NULL. | |
e70372fc PB |
81 | */ |
82 | #define QEMU_MAKE_LOCKABLE(x) \ | |
8834dcf4 PB |
83 | QEMU_GENERIC(x, \ |
84 | (QemuLockable *, (x)), \ | |
85 | qemu_make_lockable((x), QEMU_MAKE_LOCKABLE_(x))) | |
86 | ||
87 | /* QEMU_MAKE_LOCKABLE_NONNULL - Make a polymorphic QemuLockable | |
88 | * | |
89 | * @x: a lock object (currently one of QemuMutex, CoMutex, QemuSpin). | |
90 | * | |
91 | * Returns a QemuLockable object that can be passed around | |
92 | * to a function that can operate with locks of any kind. | |
93 | */ | |
94 | #define QEMU_MAKE_LOCKABLE_NONNULL(x) \ | |
e70372fc PB |
95 | QEMU_GENERIC(x, \ |
96 | (QemuLockable *, (x)), \ | |
97 | QEMU_MAKE_LOCKABLE_(x)) | |
98 | ||
99 | static inline void qemu_lockable_lock(QemuLockable *x) | |
100 | { | |
101 | x->lock(x->object); | |
102 | } | |
103 | ||
104 | static inline void qemu_lockable_unlock(QemuLockable *x) | |
105 | { | |
106 | x->unlock(x->object); | |
107 | } | |
108 | ||
3284c3dd SH |
109 | static inline QemuLockable *qemu_lockable_auto_lock(QemuLockable *x) |
110 | { | |
111 | qemu_lockable_lock(x); | |
112 | return x; | |
113 | } | |
114 | ||
115 | static inline void qemu_lockable_auto_unlock(QemuLockable *x) | |
116 | { | |
117 | if (x) { | |
118 | qemu_lockable_unlock(x); | |
119 | } | |
120 | } | |
121 | ||
122 | G_DEFINE_AUTOPTR_CLEANUP_FUNC(QemuLockable, qemu_lockable_auto_unlock) | |
123 | ||
124 | #define WITH_QEMU_LOCK_GUARD_(x, var) \ | |
125 | for (g_autoptr(QemuLockable) var = \ | |
126 | qemu_lockable_auto_lock(QEMU_MAKE_LOCKABLE_NONNULL((x))); \ | |
127 | var; \ | |
128 | qemu_lockable_auto_unlock(var), var = NULL) | |
129 | ||
130 | /** | |
131 | * WITH_QEMU_LOCK_GUARD - Lock a lock object for scope | |
132 | * | |
133 | * @x: a lock object (currently one of QemuMutex, CoMutex, QemuSpin). | |
134 | * | |
135 | * This macro defines a lock scope such that entering the scope takes the lock | |
136 | * and leaving the scope releases the lock. Return statements are allowed | |
137 | * within the scope and release the lock. Break and continue statements leave | |
138 | * the scope early and release the lock. | |
139 | * | |
140 | * WITH_QEMU_LOCK_GUARD(&mutex) { | |
141 | * ... | |
142 | * if (error) { | |
143 | * return; <-- mutex is automatically unlocked | |
144 | * } | |
145 | * | |
146 | * if (early_exit) { | |
147 | * break; <-- leave this scope early | |
148 | * } | |
149 | * ... | |
150 | * } | |
151 | */ | |
152 | #define WITH_QEMU_LOCK_GUARD(x) \ | |
153 | WITH_QEMU_LOCK_GUARD_((x), qemu_lockable_auto##__COUNTER__) | |
154 | ||
155 | /** | |
156 | * QEMU_LOCK_GUARD - Lock an object until the end of the scope | |
157 | * | |
158 | * @x: a lock object (currently one of QemuMutex, CoMutex, QemuSpin). | |
159 | * | |
160 | * This macro takes a lock until the end of the scope. Return statements | |
161 | * release the lock. | |
162 | * | |
163 | * ... <-- mutex not locked | |
164 | * QEMU_LOCK_GUARD(&mutex); <-- mutex locked from here onwards | |
165 | * ... | |
166 | * if (error) { | |
167 | * return; <-- mutex is automatically unlocked | |
168 | * } | |
169 | */ | |
170 | #define QEMU_LOCK_GUARD(x) \ | |
171 | g_autoptr(QemuLockable) qemu_lockable_auto##__COUNTER__ = \ | |
172 | qemu_lockable_auto_lock(QEMU_MAKE_LOCKABLE((x))) | |
173 | ||
e70372fc | 174 | #endif |