]>
Commit | Line | Data |
---|---|---|
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 | ||
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 | */ | |
80818e9e | 31 | #if defined(__OPTIMIZE__) && !defined(__SANITIZE_ADDRESS__) |
e70372fc PB |
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 |