xref: /qemu/include/qemu/lockable.h (revision 71920809)
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  */
31 #if defined(__OPTIMIZE__) && !defined(__SANITIZE_ADDRESS__)
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  */
68 #define QEMU_MAKE_LOCKABLE_(x) qemu_make_lockable((x), &(QemuLockable) {    \
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
79  * to a function that can operate with locks of any kind.
80  */
81 #define QEMU_MAKE_LOCKABLE(x)                        \
82     QEMU_GENERIC(x,                                  \
83                  (QemuLockable *, (x)),              \
84                  QEMU_MAKE_LOCKABLE_(x))
85 
86 static inline void qemu_lockable_lock(QemuLockable *x)
87 {
88     x->lock(x->object);
89 }
90 
91 static inline void qemu_lockable_unlock(QemuLockable *x)
92 {
93     x->unlock(x->object);
94 }
95 
96 #endif
97