]> git.ipfire.org Git - thirdparty/qemu.git/blame - include/qemu/lockable.h
lockable: add lock guards
[thirdparty/qemu.git] / include / qemu / lockable.h
CommitLineData
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
19typedef void QemuLockUnlockFunc(void *);
20
21struct 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
32void unknown_lock_type(void *);
33#else
34static inline void unknown_lock_type(void *unused)
35{
36 abort();
37}
38#endif
39
40static inline __attribute__((__always_inline__)) QemuLockable *
41qemu_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
99static inline void qemu_lockable_lock(QemuLockable *x)
100{
101 x->lock(x->object);
102}
103
104static inline void qemu_lockable_unlock(QemuLockable *x)
105{
106 x->unlock(x->object);
107}
108
3284c3dd
SH
109static inline QemuLockable *qemu_lockable_auto_lock(QemuLockable *x)
110{
111 qemu_lockable_lock(x);
112 return x;
113}
114
115static inline void qemu_lockable_auto_unlock(QemuLockable *x)
116{
117 if (x) {
118 qemu_lockable_unlock(x);
119 }
120}
121
122G_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