qemu/include/qemu/lockable.h
<<
>>
Prefs
   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
  19typedef void QemuLockUnlockFunc(void *);
  20
  21struct QemuLockable {
  22    void *object;
  23    QemuLockUnlockFunc *lock;
  24    QemuLockUnlockFunc *unlock;
  25};
  26
  27static inline __attribute__((__always_inline__)) QemuLockable *
  28qemu_make_lockable(void *x, QemuLockable *lockable)
  29{
  30    /*
  31     * We cannot test this in a macro, otherwise we get compiler
  32     * warnings like "the address of 'm' will always evaluate as 'true'".
  33     */
  34    return x ? lockable : NULL;
  35}
  36
  37static inline __attribute__((__always_inline__)) QemuLockable *
  38qemu_null_lockable(void *x)
  39{
  40    if (x != NULL) {
  41        qemu_build_not_reached();
  42    }
  43    return NULL;
  44}
  45
  46/*
  47 * In C, compound literals have the lifetime of an automatic variable.
  48 * In C++ it would be different, but then C++ wouldn't need QemuLockable
  49 * either...
  50 */
  51#define QML_OBJ_(x, name) (&(QemuLockable) {                            \
  52        .object = (x),                                                  \
  53        .lock = (QemuLockUnlockFunc *) qemu_ ## name ## _lock,          \
  54        .unlock = (QemuLockUnlockFunc *) qemu_ ## name ## _unlock       \
  55    })
  56
  57/**
  58 * QEMU_MAKE_LOCKABLE - Make a polymorphic QemuLockable
  59 *
  60 * @x: a lock object (currently one of QemuMutex, QemuRecMutex,
  61 *     CoMutex, QemuSpin).
  62 *
  63 * Returns a QemuLockable object that can be passed around
  64 * to a function that can operate with locks of any kind, or
  65 * NULL if @x is %NULL.
  66 *
  67 * Note the special case for void *, so that we may pass "NULL".
  68 */
  69#define QEMU_MAKE_LOCKABLE(x)                                           \
  70    _Generic((x), QemuLockable *: (x),                                  \
  71             void *: qemu_null_lockable(x),                             \
  72             QemuMutex *: qemu_make_lockable(x, QML_OBJ_(x, mutex)),    \
  73             QemuRecMutex *: qemu_make_lockable(x, QML_OBJ_(x, rec_mutex)), \
  74             CoMutex *: qemu_make_lockable(x, QML_OBJ_(x, co_mutex)),   \
  75             QemuSpin *: qemu_make_lockable(x, QML_OBJ_(x, spin)))
  76
  77/**
  78 * QEMU_MAKE_LOCKABLE_NONNULL - Make a polymorphic QemuLockable
  79 *
  80 * @x: a lock object (currently one of QemuMutex, QemuRecMutex,
  81 *     CoMutex, QemuSpin).
  82 *
  83 * Returns a QemuLockable object that can be passed around
  84 * to a function that can operate with locks of any kind.
  85 */
  86#define QEMU_MAKE_LOCKABLE_NONNULL(x)                           \
  87    _Generic((x), QemuLockable *: (x),                          \
  88                  QemuMutex *: QML_OBJ_(x, mutex),              \
  89                  QemuRecMutex *: QML_OBJ_(x, rec_mutex),       \
  90                  CoMutex *: QML_OBJ_(x, co_mutex),             \
  91                  QemuSpin *: QML_OBJ_(x, spin))
  92
  93static inline void qemu_lockable_lock(QemuLockable *x)
  94{
  95    x->lock(x->object);
  96}
  97
  98static inline void qemu_lockable_unlock(QemuLockable *x)
  99{
 100    x->unlock(x->object);
 101}
 102
 103static inline QemuLockable *qemu_lockable_auto_lock(QemuLockable *x)
 104{
 105    qemu_lockable_lock(x);
 106    return x;
 107}
 108
 109static inline void qemu_lockable_auto_unlock(QemuLockable *x)
 110{
 111    if (x) {
 112        qemu_lockable_unlock(x);
 113    }
 114}
 115
 116G_DEFINE_AUTOPTR_CLEANUP_FUNC(QemuLockable, qemu_lockable_auto_unlock)
 117
 118#define WITH_QEMU_LOCK_GUARD_(x, var) \
 119    for (g_autoptr(QemuLockable) var = \
 120                qemu_lockable_auto_lock(QEMU_MAKE_LOCKABLE_NONNULL((x))); \
 121         var; \
 122         qemu_lockable_auto_unlock(var), var = NULL)
 123
 124/**
 125 * WITH_QEMU_LOCK_GUARD - Lock a lock object for scope
 126 *
 127 * @x: a lock object (currently one of QemuMutex, CoMutex, QemuSpin).
 128 *
 129 * This macro defines a lock scope such that entering the scope takes the lock
 130 * and leaving the scope releases the lock.  Return statements are allowed
 131 * within the scope and release the lock.  Break and continue statements leave
 132 * the scope early and release the lock.
 133 *
 134 *   WITH_QEMU_LOCK_GUARD(&mutex) {
 135 *       ...
 136 *       if (error) {
 137 *           return; <-- mutex is automatically unlocked
 138 *       }
 139 *
 140 *       if (early_exit) {
 141 *           break;  <-- leave this scope early
 142 *       }
 143 *       ...
 144 *   }
 145 */
 146#define WITH_QEMU_LOCK_GUARD(x) \
 147    WITH_QEMU_LOCK_GUARD_((x), glue(qemu_lockable_auto, __COUNTER__))
 148
 149/**
 150 * QEMU_LOCK_GUARD - Lock an object until the end of the scope
 151 *
 152 * @x: a lock object (currently one of QemuMutex, CoMutex, QemuSpin).
 153 *
 154 * This macro takes a lock until the end of the scope.  Return statements
 155 * release the lock.
 156 *
 157 *   ... <-- mutex not locked
 158 *   QEMU_LOCK_GUARD(&mutex); <-- mutex locked from here onwards
 159 *   ...
 160 *   if (error) {
 161 *       return; <-- mutex is automatically unlocked
 162 *   }
 163 */
 164#define QEMU_LOCK_GUARD(x)                                       \
 165    g_autoptr(QemuLockable)                                      \
 166    glue(qemu_lockable_auto, __COUNTER__) G_GNUC_UNUSED =        \
 167            qemu_lockable_auto_lock(QEMU_MAKE_LOCKABLE((x)))
 168
 169#endif
 170