xref: /openbmc/qemu/include/qemu/lockable.h (revision 68ba85ce)
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 
16*68ba85ceSMarkus Armbruster #include "qemu/coroutine-core.h"
17e70372fcSPaolo Bonzini #include "qemu/thread.h"
18e70372fcSPaolo Bonzini 
19e70372fcSPaolo Bonzini typedef void QemuLockUnlockFunc(void *);
20e70372fcSPaolo Bonzini 
21e70372fcSPaolo Bonzini struct QemuLockable {
22e70372fcSPaolo Bonzini     void *object;
23e70372fcSPaolo Bonzini     QemuLockUnlockFunc *lock;
24e70372fcSPaolo Bonzini     QemuLockUnlockFunc *unlock;
25e70372fcSPaolo Bonzini };
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 
464ffb0681SRichard Henderson /*
474ffb0681SRichard Henderson  * In C, compound literals have the lifetime of an automatic variable.
48e70372fcSPaolo Bonzini  * In C++ it would be different, but then C++ wouldn't need QemuLockable
49e70372fcSPaolo Bonzini  * either...
50e70372fcSPaolo Bonzini  */
514ffb0681SRichard Henderson #define QML_OBJ_(x, name) (&(QemuLockable) {                            \
52e70372fcSPaolo Bonzini         .object = (x),                                                  \
534ffb0681SRichard Henderson         .lock = (QemuLockUnlockFunc *) qemu_ ## name ## _lock,          \
544ffb0681SRichard Henderson         .unlock = (QemuLockUnlockFunc *) qemu_ ## name ## _unlock       \
55e70372fcSPaolo Bonzini     })
56e70372fcSPaolo Bonzini 
574ffb0681SRichard Henderson /**
584ffb0681SRichard Henderson  * QEMU_MAKE_LOCKABLE - Make a polymorphic QemuLockable
59e70372fcSPaolo Bonzini  *
604ffb0681SRichard Henderson  * @x: a lock object (currently one of QemuMutex, QemuRecMutex,
614ffb0681SRichard Henderson  *     CoMutex, QemuSpin).
62e70372fcSPaolo Bonzini  *
63e70372fcSPaolo Bonzini  * Returns a QemuLockable object that can be passed around
648834dcf4SPaolo Bonzini  * to a function that can operate with locks of any kind, or
658834dcf4SPaolo Bonzini  * NULL if @x is %NULL.
664ffb0681SRichard Henderson  *
674ffb0681SRichard Henderson  * Note the special case for void *, so that we may pass "NULL".
68e70372fcSPaolo Bonzini  */
69e70372fcSPaolo Bonzini #define QEMU_MAKE_LOCKABLE(x)                                           \
704ffb0681SRichard Henderson     _Generic((x), QemuLockable *: (x),                                  \
714ffb0681SRichard Henderson              void *: qemu_null_lockable(x),                             \
724ffb0681SRichard Henderson              QemuMutex *: qemu_make_lockable(x, QML_OBJ_(x, mutex)),    \
734ffb0681SRichard Henderson              QemuRecMutex *: qemu_make_lockable(x, QML_OBJ_(x, rec_mutex)), \
744ffb0681SRichard Henderson              CoMutex *: qemu_make_lockable(x, QML_OBJ_(x, co_mutex)),   \
754ffb0681SRichard Henderson              QemuSpin *: qemu_make_lockable(x, QML_OBJ_(x, spin)))
768834dcf4SPaolo Bonzini 
774ffb0681SRichard Henderson /**
784ffb0681SRichard Henderson  * QEMU_MAKE_LOCKABLE_NONNULL - Make a polymorphic QemuLockable
798834dcf4SPaolo Bonzini  *
804ffb0681SRichard Henderson  * @x: a lock object (currently one of QemuMutex, QemuRecMutex,
814ffb0681SRichard Henderson  *     CoMutex, QemuSpin).
828834dcf4SPaolo Bonzini  *
838834dcf4SPaolo Bonzini  * Returns a QemuLockable object that can be passed around
848834dcf4SPaolo Bonzini  * to a function that can operate with locks of any kind.
858834dcf4SPaolo Bonzini  */
868834dcf4SPaolo Bonzini #define QEMU_MAKE_LOCKABLE_NONNULL(x)                           \
874ffb0681SRichard Henderson     _Generic((x), QemuLockable *: (x),                          \
884ffb0681SRichard Henderson                   QemuMutex *: QML_OBJ_(x, mutex),              \
894ffb0681SRichard Henderson                   QemuRecMutex *: QML_OBJ_(x, rec_mutex),       \
904ffb0681SRichard Henderson                   CoMutex *: QML_OBJ_(x, co_mutex),             \
914ffb0681SRichard Henderson                   QemuSpin *: QML_OBJ_(x, spin))
92e70372fcSPaolo Bonzini 
qemu_lockable_lock(QemuLockable * x)93e70372fcSPaolo Bonzini static inline void qemu_lockable_lock(QemuLockable *x)
94e70372fcSPaolo Bonzini {
95e70372fcSPaolo Bonzini     x->lock(x->object);
96e70372fcSPaolo Bonzini }
97e70372fcSPaolo Bonzini 
qemu_lockable_unlock(QemuLockable * x)98e70372fcSPaolo Bonzini static inline void qemu_lockable_unlock(QemuLockable *x)
99e70372fcSPaolo Bonzini {
100e70372fcSPaolo Bonzini     x->unlock(x->object);
101e70372fcSPaolo Bonzini }
102e70372fcSPaolo Bonzini 
qemu_lockable_auto_lock(QemuLockable * x)1033284c3ddSStefan Hajnoczi static inline QemuLockable *qemu_lockable_auto_lock(QemuLockable *x)
1043284c3ddSStefan Hajnoczi {
1053284c3ddSStefan Hajnoczi     qemu_lockable_lock(x);
1063284c3ddSStefan Hajnoczi     return x;
1073284c3ddSStefan Hajnoczi }
1083284c3ddSStefan Hajnoczi 
qemu_lockable_auto_unlock(QemuLockable * x)1093284c3ddSStefan Hajnoczi static inline void qemu_lockable_auto_unlock(QemuLockable *x)
1103284c3ddSStefan Hajnoczi {
1113284c3ddSStefan Hajnoczi     if (x) {
1123284c3ddSStefan Hajnoczi         qemu_lockable_unlock(x);
1133284c3ddSStefan Hajnoczi     }
1143284c3ddSStefan Hajnoczi }
1153284c3ddSStefan Hajnoczi 
1163284c3ddSStefan Hajnoczi G_DEFINE_AUTOPTR_CLEANUP_FUNC(QemuLockable, qemu_lockable_auto_unlock)
1173284c3ddSStefan Hajnoczi 
1183284c3ddSStefan Hajnoczi #define WITH_QEMU_LOCK_GUARD_(x, var) \
1193284c3ddSStefan Hajnoczi     for (g_autoptr(QemuLockable) var = \
1203284c3ddSStefan Hajnoczi                 qemu_lockable_auto_lock(QEMU_MAKE_LOCKABLE_NONNULL((x))); \
1213284c3ddSStefan Hajnoczi          var; \
1223284c3ddSStefan Hajnoczi          qemu_lockable_auto_unlock(var), var = NULL)
1233284c3ddSStefan Hajnoczi 
1243284c3ddSStefan Hajnoczi /**
1253284c3ddSStefan Hajnoczi  * WITH_QEMU_LOCK_GUARD - Lock a lock object for scope
1263284c3ddSStefan Hajnoczi  *
1273284c3ddSStefan Hajnoczi  * @x: a lock object (currently one of QemuMutex, CoMutex, QemuSpin).
1283284c3ddSStefan Hajnoczi  *
1293284c3ddSStefan Hajnoczi  * This macro defines a lock scope such that entering the scope takes the lock
1303284c3ddSStefan Hajnoczi  * and leaving the scope releases the lock.  Return statements are allowed
1313284c3ddSStefan Hajnoczi  * within the scope and release the lock.  Break and continue statements leave
1323284c3ddSStefan Hajnoczi  * the scope early and release the lock.
1333284c3ddSStefan Hajnoczi  *
1343284c3ddSStefan Hajnoczi  *   WITH_QEMU_LOCK_GUARD(&mutex) {
1353284c3ddSStefan Hajnoczi  *       ...
1363284c3ddSStefan Hajnoczi  *       if (error) {
1373284c3ddSStefan Hajnoczi  *           return; <-- mutex is automatically unlocked
1383284c3ddSStefan Hajnoczi  *       }
1393284c3ddSStefan Hajnoczi  *
1403284c3ddSStefan Hajnoczi  *       if (early_exit) {
1413284c3ddSStefan Hajnoczi  *           break;  <-- leave this scope early
1423284c3ddSStefan Hajnoczi  *       }
1433284c3ddSStefan Hajnoczi  *       ...
1443284c3ddSStefan Hajnoczi  *   }
1453284c3ddSStefan Hajnoczi  */
1463284c3ddSStefan Hajnoczi #define WITH_QEMU_LOCK_GUARD(x) \
14756f21718SDaniel Brodsky     WITH_QEMU_LOCK_GUARD_((x), glue(qemu_lockable_auto, __COUNTER__))
1483284c3ddSStefan Hajnoczi 
1493284c3ddSStefan Hajnoczi /**
1503284c3ddSStefan Hajnoczi  * QEMU_LOCK_GUARD - Lock an object until the end of the scope
1513284c3ddSStefan Hajnoczi  *
1523284c3ddSStefan Hajnoczi  * @x: a lock object (currently one of QemuMutex, CoMutex, QemuSpin).
1533284c3ddSStefan Hajnoczi  *
1543284c3ddSStefan Hajnoczi  * This macro takes a lock until the end of the scope.  Return statements
1553284c3ddSStefan Hajnoczi  * release the lock.
1563284c3ddSStefan Hajnoczi  *
1573284c3ddSStefan Hajnoczi  *   ... <-- mutex not locked
1583284c3ddSStefan Hajnoczi  *   QEMU_LOCK_GUARD(&mutex); <-- mutex locked from here onwards
1593284c3ddSStefan Hajnoczi  *   ...
1603284c3ddSStefan Hajnoczi  *   if (error) {
1613284c3ddSStefan Hajnoczi  *       return; <-- mutex is automatically unlocked
1623284c3ddSStefan Hajnoczi  *   }
1633284c3ddSStefan Hajnoczi  */
1643284c3ddSStefan Hajnoczi #define QEMU_LOCK_GUARD(x)                                       \
16556f21718SDaniel Brodsky     g_autoptr(QemuLockable)                                      \
16656f21718SDaniel Brodsky     glue(qemu_lockable_auto, __COUNTER__) G_GNUC_UNUSED =        \
1673284c3ddSStefan Hajnoczi             qemu_lockable_auto_lock(QEMU_MAKE_LOCKABLE((x)))
1683284c3ddSStefan Hajnoczi 
169e70372fcSPaolo Bonzini #endif
170