1e70372fcSPaolo Bonzini /*
2e70372fcSPaolo Bonzini * Polymorphic locking functions (aka poor man templates)
3e70372fcSPaolo Bonzini *
4e70372fcSPaolo Bonzini * Copyright Red Hat, Inc. 2017, 2018
5e70372fcSPaolo Bonzini *
6e70372fcSPaolo Bonzini * Author: Paolo Bonzini <pbonzini@redhat.com>
7e70372fcSPaolo Bonzini *
8e70372fcSPaolo Bonzini * This work is licensed under the terms of the GNU LGPL, version 2 or later.
9e70372fcSPaolo Bonzini * See the COPYING.LIB file in the top-level directory.
10e70372fcSPaolo Bonzini *
11e70372fcSPaolo Bonzini */
12e70372fcSPaolo Bonzini
13e70372fcSPaolo Bonzini #ifndef QEMU_LOCKABLE_H
14e70372fcSPaolo Bonzini #define QEMU_LOCKABLE_H
15e70372fcSPaolo Bonzini
1668ba85ceSMarkus Armbruster #include "qemu/coroutine-core.h"
17e70372fcSPaolo Bonzini #include "qemu/thread.h"
18e70372fcSPaolo Bonzini
19e70372fcSPaolo Bonzini typedef void QemuLockUnlockFunc(void *);
20e70372fcSPaolo Bonzini
2113d11094SPaolo Bonzini typedef struct QemuLockable {
22e70372fcSPaolo Bonzini void *object;
23e70372fcSPaolo Bonzini QemuLockUnlockFunc *lock;
24e70372fcSPaolo Bonzini QemuLockUnlockFunc *unlock;
2513d11094SPaolo Bonzini } QemuLockable;
26e70372fcSPaolo Bonzini
27e70372fcSPaolo Bonzini static inline __attribute__((__always_inline__)) QemuLockable *
qemu_make_lockable(void * x,QemuLockable * lockable)28e70372fcSPaolo Bonzini qemu_make_lockable(void *x, QemuLockable *lockable)
29e70372fcSPaolo Bonzini {
304ffb0681SRichard Henderson /*
314ffb0681SRichard Henderson * We cannot test this in a macro, otherwise we get compiler
32e70372fcSPaolo Bonzini * warnings like "the address of 'm' will always evaluate as 'true'".
33e70372fcSPaolo Bonzini */
34e70372fcSPaolo Bonzini return x ? lockable : NULL;
35e70372fcSPaolo Bonzini }
36e70372fcSPaolo Bonzini
374ffb0681SRichard Henderson static inline __attribute__((__always_inline__)) QemuLockable *
qemu_null_lockable(void * x)384ffb0681SRichard Henderson qemu_null_lockable(void *x)
394ffb0681SRichard Henderson {
404ffb0681SRichard Henderson if (x != NULL) {
414ffb0681SRichard Henderson qemu_build_not_reached();
424ffb0681SRichard Henderson }
434ffb0681SRichard Henderson return NULL;
444ffb0681SRichard Henderson }
45e70372fcSPaolo Bonzini
46*a3b3ad72SAkihiko Odaki #define QML_FUNC_(name) \
47*a3b3ad72SAkihiko Odaki static inline void qemu_lockable_ ## name ## _lock(void *x) \
48*a3b3ad72SAkihiko Odaki { \
49*a3b3ad72SAkihiko Odaki qemu_ ## name ## _lock(x); \
50*a3b3ad72SAkihiko Odaki } \
51*a3b3ad72SAkihiko Odaki static inline void qemu_lockable_ ## name ## _unlock(void *x) \
52*a3b3ad72SAkihiko Odaki { \
53*a3b3ad72SAkihiko Odaki qemu_ ## name ## _unlock(x); \
54*a3b3ad72SAkihiko Odaki }
55*a3b3ad72SAkihiko Odaki
56*a3b3ad72SAkihiko Odaki QML_FUNC_(mutex)
QML_FUNC_(rec_mutex)57*a3b3ad72SAkihiko Odaki QML_FUNC_(rec_mutex)
58*a3b3ad72SAkihiko Odaki QML_FUNC_(co_mutex)
59*a3b3ad72SAkihiko Odaki QML_FUNC_(spin)
60*a3b3ad72SAkihiko Odaki
614ffb0681SRichard Henderson /*
624ffb0681SRichard Henderson * In C, compound literals have the lifetime of an automatic variable.
63e70372fcSPaolo Bonzini * In C++ it would be different, but then C++ wouldn't need QemuLockable
64e70372fcSPaolo Bonzini * either...
65e70372fcSPaolo Bonzini */
664ffb0681SRichard Henderson #define QML_OBJ_(x, name) (&(QemuLockable) { \
67e70372fcSPaolo Bonzini .object = (x), \
68*a3b3ad72SAkihiko Odaki .lock = qemu_lockable_ ## name ## _lock, \
69*a3b3ad72SAkihiko Odaki .unlock = qemu_lockable_ ## name ## _unlock \
70e70372fcSPaolo Bonzini })
71e70372fcSPaolo Bonzini
724ffb0681SRichard Henderson /**
734ffb0681SRichard Henderson * QEMU_MAKE_LOCKABLE - Make a polymorphic QemuLockable
74e70372fcSPaolo Bonzini *
754ffb0681SRichard Henderson * @x: a lock object (currently one of QemuMutex, QemuRecMutex,
764ffb0681SRichard Henderson * CoMutex, QemuSpin).
77e70372fcSPaolo Bonzini *
78e70372fcSPaolo Bonzini * Returns a QemuLockable object that can be passed around
798834dcf4SPaolo Bonzini * to a function that can operate with locks of any kind, or
808834dcf4SPaolo Bonzini * NULL if @x is %NULL.
814ffb0681SRichard Henderson *
824ffb0681SRichard Henderson * Note the special case for void *, so that we may pass "NULL".
83e70372fcSPaolo Bonzini */
84e70372fcSPaolo Bonzini #define QEMU_MAKE_LOCKABLE(x) \
854ffb0681SRichard Henderson _Generic((x), QemuLockable *: (x), \
864ffb0681SRichard Henderson void *: qemu_null_lockable(x), \
874ffb0681SRichard Henderson QemuMutex *: qemu_make_lockable(x, QML_OBJ_(x, mutex)), \
884ffb0681SRichard Henderson QemuRecMutex *: qemu_make_lockable(x, QML_OBJ_(x, rec_mutex)), \
894ffb0681SRichard Henderson CoMutex *: qemu_make_lockable(x, QML_OBJ_(x, co_mutex)), \
904ffb0681SRichard Henderson QemuSpin *: qemu_make_lockable(x, QML_OBJ_(x, spin)))
918834dcf4SPaolo Bonzini
924ffb0681SRichard Henderson /**
934ffb0681SRichard Henderson * QEMU_MAKE_LOCKABLE_NONNULL - Make a polymorphic QemuLockable
948834dcf4SPaolo Bonzini *
954ffb0681SRichard Henderson * @x: a lock object (currently one of QemuMutex, QemuRecMutex,
964ffb0681SRichard Henderson * CoMutex, QemuSpin).
978834dcf4SPaolo Bonzini *
988834dcf4SPaolo Bonzini * Returns a QemuLockable object that can be passed around
998834dcf4SPaolo Bonzini * to a function that can operate with locks of any kind.
1008834dcf4SPaolo Bonzini */
1018834dcf4SPaolo Bonzini #define QEMU_MAKE_LOCKABLE_NONNULL(x) \
1024ffb0681SRichard Henderson _Generic((x), QemuLockable *: (x), \
1034ffb0681SRichard Henderson QemuMutex *: QML_OBJ_(x, mutex), \
1044ffb0681SRichard Henderson QemuRecMutex *: QML_OBJ_(x, rec_mutex), \
1054ffb0681SRichard Henderson CoMutex *: QML_OBJ_(x, co_mutex), \
1064ffb0681SRichard Henderson QemuSpin *: QML_OBJ_(x, spin))
107e70372fcSPaolo Bonzini
108e70372fcSPaolo Bonzini static inline void qemu_lockable_lock(QemuLockable *x)
109e70372fcSPaolo Bonzini {
110e70372fcSPaolo Bonzini x->lock(x->object);
111e70372fcSPaolo Bonzini }
112e70372fcSPaolo Bonzini
qemu_lockable_unlock(QemuLockable * x)113e70372fcSPaolo Bonzini static inline void qemu_lockable_unlock(QemuLockable *x)
114e70372fcSPaolo Bonzini {
115e70372fcSPaolo Bonzini x->unlock(x->object);
116e70372fcSPaolo Bonzini }
117e70372fcSPaolo Bonzini
qemu_lockable_auto_lock(QemuLockable * x)1183284c3ddSStefan Hajnoczi static inline QemuLockable *qemu_lockable_auto_lock(QemuLockable *x)
1193284c3ddSStefan Hajnoczi {
1203284c3ddSStefan Hajnoczi qemu_lockable_lock(x);
1213284c3ddSStefan Hajnoczi return x;
1223284c3ddSStefan Hajnoczi }
1233284c3ddSStefan Hajnoczi
qemu_lockable_auto_unlock(QemuLockable * x)1243284c3ddSStefan Hajnoczi static inline void qemu_lockable_auto_unlock(QemuLockable *x)
1253284c3ddSStefan Hajnoczi {
1263284c3ddSStefan Hajnoczi if (x) {
1273284c3ddSStefan Hajnoczi qemu_lockable_unlock(x);
1283284c3ddSStefan Hajnoczi }
1293284c3ddSStefan Hajnoczi }
1303284c3ddSStefan Hajnoczi
1313284c3ddSStefan Hajnoczi G_DEFINE_AUTOPTR_CLEANUP_FUNC(QemuLockable, qemu_lockable_auto_unlock)
1323284c3ddSStefan Hajnoczi
1333284c3ddSStefan Hajnoczi #define WITH_QEMU_LOCK_GUARD_(x, var) \
1343284c3ddSStefan Hajnoczi for (g_autoptr(QemuLockable) var = \
1353284c3ddSStefan Hajnoczi qemu_lockable_auto_lock(QEMU_MAKE_LOCKABLE_NONNULL((x))); \
1363284c3ddSStefan Hajnoczi var; \
1373284c3ddSStefan Hajnoczi qemu_lockable_auto_unlock(var), var = NULL)
1383284c3ddSStefan Hajnoczi
1393284c3ddSStefan Hajnoczi /**
1403284c3ddSStefan Hajnoczi * WITH_QEMU_LOCK_GUARD - Lock a lock object for scope
1413284c3ddSStefan Hajnoczi *
1423284c3ddSStefan Hajnoczi * @x: a lock object (currently one of QemuMutex, CoMutex, QemuSpin).
1433284c3ddSStefan Hajnoczi *
1443284c3ddSStefan Hajnoczi * This macro defines a lock scope such that entering the scope takes the lock
1453284c3ddSStefan Hajnoczi * and leaving the scope releases the lock. Return statements are allowed
1463284c3ddSStefan Hajnoczi * within the scope and release the lock. Break and continue statements leave
1473284c3ddSStefan Hajnoczi * the scope early and release the lock.
1483284c3ddSStefan Hajnoczi *
1493284c3ddSStefan Hajnoczi * WITH_QEMU_LOCK_GUARD(&mutex) {
1503284c3ddSStefan Hajnoczi * ...
1513284c3ddSStefan Hajnoczi * if (error) {
1523284c3ddSStefan Hajnoczi * return; <-- mutex is automatically unlocked
1533284c3ddSStefan Hajnoczi * }
1543284c3ddSStefan Hajnoczi *
1553284c3ddSStefan Hajnoczi * if (early_exit) {
1563284c3ddSStefan Hajnoczi * break; <-- leave this scope early
1573284c3ddSStefan Hajnoczi * }
1583284c3ddSStefan Hajnoczi * ...
1593284c3ddSStefan Hajnoczi * }
1603284c3ddSStefan Hajnoczi */
1613284c3ddSStefan Hajnoczi #define WITH_QEMU_LOCK_GUARD(x) \
16256f21718SDaniel Brodsky WITH_QEMU_LOCK_GUARD_((x), glue(qemu_lockable_auto, __COUNTER__))
1633284c3ddSStefan Hajnoczi
1643284c3ddSStefan Hajnoczi /**
1653284c3ddSStefan Hajnoczi * QEMU_LOCK_GUARD - Lock an object until the end of the scope
1663284c3ddSStefan Hajnoczi *
1673284c3ddSStefan Hajnoczi * @x: a lock object (currently one of QemuMutex, CoMutex, QemuSpin).
1683284c3ddSStefan Hajnoczi *
1693284c3ddSStefan Hajnoczi * This macro takes a lock until the end of the scope. Return statements
1703284c3ddSStefan Hajnoczi * release the lock.
1713284c3ddSStefan Hajnoczi *
1723284c3ddSStefan Hajnoczi * ... <-- mutex not locked
1733284c3ddSStefan Hajnoczi * QEMU_LOCK_GUARD(&mutex); <-- mutex locked from here onwards
1743284c3ddSStefan Hajnoczi * ...
1753284c3ddSStefan Hajnoczi * if (error) {
1763284c3ddSStefan Hajnoczi * return; <-- mutex is automatically unlocked
1773284c3ddSStefan Hajnoczi * }
1783284c3ddSStefan Hajnoczi */
1793284c3ddSStefan Hajnoczi #define QEMU_LOCK_GUARD(x) \
18056f21718SDaniel Brodsky g_autoptr(QemuLockable) \
18156f21718SDaniel Brodsky glue(qemu_lockable_auto, __COUNTER__) G_GNUC_UNUSED = \
1823284c3ddSStefan Hajnoczi qemu_lockable_auto_lock(QEMU_MAKE_LOCKABLE((x)))
1833284c3ddSStefan Hajnoczi
184e70372fcSPaolo Bonzini #endif
185