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