Skip to content

Bit Spinlock

include/sync/bit_spinlock.h View source View on GitHub
#define BIT_SPINLOCK_MASK(bit, ptr) ((typeof(*(ptr))) (1ULL << (bit)))
#define BIT_SPINLOCK_CHECK(bit, ptr) \
    do { \
        static_assert(__builtin_constant_p(bit) \
                          ? ((size_t) (bit) < sizeof(*(ptr)) * 8) \
                          : 1, \
                      "bit index exceeds type width"); \
        kassert((size_t) (bit) < sizeof(*(ptr)) * 8, \
                "bit index out of bounds for pointer type"); \
    } while (0)
#define bit_spin_is_locked_raw(bit, ptr) \
    ({ \
        BIT_SPINLOCK_CHECK(bit, ptr); \
        typeof(*(ptr)) __m = BIT_SPINLOCK_MASK(bit, ptr); \
        (atomic_load_explicit((_Atomic typeof(*(ptr)) *) (ptr), \
                              memory_order_relaxed) & \
         __m) != 0; \
    })
#define bit_spin_trylock_raw(bit, ptr) \
    ({ \
        BIT_SPINLOCK_CHECK(bit, ptr); \
        typeof(*(ptr)) __m = BIT_SPINLOCK_MASK(bit, ptr); \
        typeof(*(ptr)) __old = atomic_load_explicit( \
            (_Atomic typeof(*(ptr)) *) (ptr), memory_order_relaxed); \
        bool __acquired = false; \
        if (!(__old & __m)) { \
            __acquired = atomic_compare_exchange_weak_explicit( \
                (_Atomic typeof(*(ptr)) *) (ptr), &__old, \
                (typeof(*(ptr))) (__old | __m), memory_order_acquire, \
                memory_order_relaxed); \
        } \
        __acquired; \
    })
#define bit_spin_lock_raw(bit, ptr) \
    do { \
        BIT_SPINLOCK_CHECK(bit, ptr); \
        typeof(*(ptr)) __m = BIT_SPINLOCK_MASK(bit, ptr); \
        while (true) { \
            typeof(*(ptr)) __old = atomic_load_explicit( \
                (_Atomic typeof(*(ptr)) *) (ptr), memory_order_relaxed); \
            if (__old & __m) { \
                cpu_relax(); \
                continue; \
            } \
            if (atomic_compare_exchange_weak_explicit( \
                    (_Atomic typeof(*(ptr)) *) (ptr), &__old, \
                    (typeof(*(ptr))) (__old | __m), memory_order_acquire, \
                    memory_order_relaxed)) \
                break; \
            cpu_relax(); \
        } \
    } while (0)
#define bit_spin_unlock_raw(bit, ptr) \
    do { \
        BIT_SPINLOCK_CHECK(bit, ptr); \
        typeof(*(ptr)) __m = BIT_SPINLOCK_MASK(bit, ptr); \
        typeof(*(ptr)) __not_m = (typeof(*(ptr))) (~__m); \
        kassert(atomic_fetch_and_explicit((_Atomic typeof(*(ptr)) *) (ptr), \
                                          __not_m, memory_order_release) & \
                    __m, \
                "bit spinlock unlock on unheld lock"); \
    } while (0)
#define bit_spin_lock(bit, ptr) \
    ({ \
        enum irql __old_irql = irql_raise(IRQL_DISPATCH_LEVEL); \
        bit_spin_lock_raw(bit, ptr); \
        __old_irql; \
    })
#define bit_spin_unlock(bit, ptr, old_irql) \
    do { \
        bit_spin_unlock_raw(bit, ptr); \
        irql_lower(old_irql); \
    } while (0)
#define bit_spin_lock_irq_disable(bit, ptr) \
    ({ \
        enum irql __old_irql = irql_raise(IRQL_HIGH_LEVEL); \
        bit_spin_lock_raw(bit, ptr); \
        __old_irql; \
    })
#define bit_spin_unlock_irq_restore(bit, ptr, old_irql) \
    do { \
        bit_spin_unlock_raw(bit, ptr); \
        irql_lower(old_irql); \
    } while (0)
#define bit_spin_trylock(bit, ptr, out_irql) \
    ({ \
        *(out_irql) = irql_raise(IRQL_DISPATCH_LEVEL); \
        bool __ok = bit_spin_trylock_raw(bit, ptr); \
        if (!__ok) \
            irql_lower(*(out_irql)); \
        __ok; \
    })
#define bit_spin_trylock_irq_disable(bit, ptr, out_irql) \
    ({ \
        *(out_irql) = irql_raise(IRQL_HIGH_LEVEL); \
        bool __ok = bit_spin_trylock_raw(bit, ptr); \
        if (!__ok) \
            irql_lower(*(out_irql)); \
        __ok; \
    })
#define BIT_SPIN_LOCK_ASSERT_HELD(bit, ptr) \
    kassert(bit_spin_is_locked_raw(bit, ptr), "bitlock not held")