xref: /qemu/include/qemu/lockable.h (revision a3b3ad72)
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