]> git.proxmox.com Git - mirror_qemu.git/blame - include/qemu/lockable.h
Merge tag 'for-upstream' of https://repo.or.cz/qemu/kevin into staging
[mirror_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
68ba85ce 16#include "qemu/coroutine-core.h"
e70372fc
PB
17#include "qemu/thread.h"
18
19typedef void QemuLockUnlockFunc(void *);
20
21struct QemuLockable {
22 void *object;
23 QemuLockUnlockFunc *lock;
24 QemuLockUnlockFunc *unlock;
25};
26
e70372fc
PB
27static inline __attribute__((__always_inline__)) QemuLockable *
28qemu_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
37static inline __attribute__((__always_inline__)) QemuLockable *
38qemu_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
93static inline void qemu_lockable_lock(QemuLockable *x)
94{
95 x->lock(x->object);
96}
97
98static inline void qemu_lockable_unlock(QemuLockable *x)
99{
100 x->unlock(x->object);
101}
102
3284c3dd
SH
103static inline QemuLockable *qemu_lockable_auto_lock(QemuLockable *x)
104{
105 qemu_lockable_lock(x);
106 return x;
107}
108
109static inline void qemu_lockable_auto_unlock(QemuLockable *x)
110{
111 if (x) {
112 qemu_lockable_unlock(x);
113 }
114}
115
116G_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