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 | |