]>
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 | ||
e70372fc PB |
27 | static inline __attribute__((__always_inline__)) QemuLockable * |
28 | qemu_make_lockable(void *x, QemuLockable *lockable) | |
29 | { | |
4ffb0681 RH |
30 | /* |
31 | * We cannot test this in a macro, otherwise we get compiler | |
e70372fc PB |
32 | * warnings like "the address of 'm' will always evaluate as 'true'". |
33 | */ | |
34 | return x ? lockable : NULL; | |
35 | } | |
36 | ||
4ffb0681 RH |
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 | } | |
e70372fc | 45 | |
4ffb0681 RH |
46 | /* |
47 | * In C, compound literals have the lifetime of an automatic variable. | |
e70372fc PB |
48 | * In C++ it would be different, but then C++ wouldn't need QemuLockable |
49 | * either... | |
50 | */ | |
4ffb0681 RH |
51 | #define QML_OBJ_(x, name) (&(QemuLockable) { \ |
52 | .object = (x), \ | |
53 | .lock = (QemuLockUnlockFunc *) qemu_ ## name ## _lock, \ | |
54 | .unlock = (QemuLockUnlockFunc *) qemu_ ## name ## _unlock \ | |
e70372fc PB |
55 | }) |
56 | ||
4ffb0681 RH |
57 | /** |
58 | * QEMU_MAKE_LOCKABLE - Make a polymorphic QemuLockable | |
e70372fc | 59 | * |
4ffb0681 RH |
60 | * @x: a lock object (currently one of QemuMutex, QemuRecMutex, |
61 | * CoMutex, QemuSpin). | |
e70372fc PB |
62 | * |
63 | * Returns a QemuLockable object that can be passed around | |
8834dcf4 PB |
64 | * to a function that can operate with locks of any kind, or |
65 | * NULL if @x is %NULL. | |
4ffb0681 RH |
66 | * |
67 | * Note the special case for void *, so that we may pass "NULL". | |
e70372fc | 68 | */ |
4ffb0681 RH |
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))) | |
8834dcf4 | 76 | |
4ffb0681 RH |
77 | /** |
78 | * QEMU_MAKE_LOCKABLE_NONNULL - Make a polymorphic QemuLockable | |
8834dcf4 | 79 | * |
4ffb0681 RH |
80 | * @x: a lock object (currently one of QemuMutex, QemuRecMutex, |
81 | * CoMutex, QemuSpin). | |
8834dcf4 PB |
82 | * |
83 | * Returns a QemuLockable object that can be passed around | |
84 | * to a function that can operate with locks of any kind. | |
85 | */ | |
4ffb0681 RH |
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)) | |
e70372fc PB |
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 | ||
3284c3dd SH |
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) \ | |
56f21718 | 147 | WITH_QEMU_LOCK_GUARD_((x), glue(qemu_lockable_auto, __COUNTER__)) |
3284c3dd SH |
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 | */ | |
56f21718 DB |
164 | #define QEMU_LOCK_GUARD(x) \ |
165 | g_autoptr(QemuLockable) \ | |
166 | glue(qemu_lockable_auto, __COUNTER__) G_GNUC_UNUSED = \ | |
3284c3dd SH |
167 | qemu_lockable_auto_lock(QEMU_MAKE_LOCKABLE((x))) |
168 | ||
e70372fc | 169 | #endif |