Skip to content

Queued Spinlock (MCS-based 4-byte qspinlock)

include/sync/qspinlock.h View source View on GitHub
TODO

I would really like to use a CNA lock/cohorting as an extension to qspinlock, possibly also with a boot-time flag to enable/disable it for testing. Could be super interesting!

struct qspinlock_acq_scope (3 fields) source
§ struct lock_chk_acq_req req
§ struct lock_chk_acq_token token
§ bool checked
struct qspinlock_rel_scope (3 fields) source
§ struct lock_chk_rel_req req
§ struct lock_chk_rel_token token
§ bool checked
struct qspinlock_acq_scope (1 field) source
§ char unused_
struct qspinlock_rel_scope (1 field) source
§ char unused_
struct qspinlock_guard (2 fields) source
§ struct qspinlock *lock
§ enum irql irql
enum qspinlock_level (4 variants) source
§ QSPINLOCK_LEVEL_NORMAL

prev irql = DISPATCH

§ QSPINLOCK_LEVEL_IRQ

prev irql = HIGH

§ QSPINLOCK_LEVEL_NMI

For later usage

§ QSPINLOCK_LEVEL_MAX
void qspinlock_init_chk_full(
    struct qspinlock *lock,
    const struct lock_chk_class *class,
    enum lock_chk_flags flags
)
source
bool qspin_is_locked(const struct qspinlock *lock)
source
void qspinlock_policy_init_internal(
    struct qspinlock *lock,
    enum lock_chk_flags flags
)
source
void qspinlock_map_init_internal(
    struct qspinlock *lock,
    const struct lock_chk_class *class,
    enum lock_chk_flags flags
)
source
void qspinlock_shallow_init_internal(struct qspinlock *lock)
source
void qspinlock_set_chk_flags(
    struct qspinlock *lock,
    enum lock_chk_flags flags
)
source
void qspinlock_reinit_chk(
    struct qspinlock *lock,
    const struct lock_chk_class *class,
    enum lock_chk_flags flags
)
source
void qspinlock_note_use(
    struct qspinlock *lock,
    enum lock_op_flags flags
)
source
bool qspinlock_order_checked(struct qspinlock *lock)
source
void qspinlock_stamp(struct qspinlock *lock)
source
TODO

move stamping to initialization, but we are using this HACK: because it’s fine anyways

void qspinlock_classify(
    struct qspinlock *lock,
    enum lock_op_flags usage,
    const struct lock_chk_site *site
)
source
bool qspinlock_deep_checked(struct qspinlock *lock)
source
struct lock_chk_acq_req qspinlock_chk_acq_req(
    struct qspinlock *lock,
    const struct lock_chk_site *site,
    enum lock_subclass subclass,
    enum lock_op_flags flags
)
source
struct lock_chk_rel_req qspinlock_chk_rel_req(
    struct qspinlock *lock,
    const struct lock_chk_site *site
)
source
void qspinlock_acq_begin(
    struct qspinlock_acq_scope *scope,
    struct qspinlock *lock,
    const struct lock_chk_site *site,
    enum lock_subclass subclass,
    enum lock_op_flags flags
)
source
void qspinlock_acq_commit(struct qspinlock_acq_scope *scope)
source
void qspinlock_acq_abort(struct qspinlock_acq_scope *scope)
source
void qspinlock_rel_begin(
    struct qspinlock_rel_scope *scope,
    struct qspinlock *lock,
    const struct lock_chk_site *site
)
source
void qspinlock_rel_commit(struct qspinlock_rel_scope *scope)
source
void qspinlock_shallow_push(
    struct qspinlock *lock,
    enum irql irql,
    const struct lock_chk_site *site
)
source
void qspinlock_shallow_validate_top(
    struct qspinlock *lock,
    enum irql old,
    const struct lock_chk_site *site
)
source
void qspinlock_shallow_pop(struct qspinlock *lock)
source
bool qspinlock_assert_held_deep(
    struct qspinlock *lock,
    bool want_held,
    const struct lock_chk_site *site
)
source
void qspinlock_policy_init_internal(
    struct qspinlock *lock,
    enum lock_chk_flags flags
)
source
void qspinlock_map_init_internal(
    struct qspinlock *lock,
    const struct lock_chk_class *class,
    enum lock_chk_flags flags
)
source
void qspinlock_shallow_init_internal(struct qspinlock *lock)
source
void qspinlock_set_chk_flags(
    struct qspinlock *lock,
    enum lock_chk_flags flags
)
source
void qspinlock_reinit_chk(
    struct qspinlock *lock,
    const struct lock_chk_class *class,
    enum lock_chk_flags flags
)
source
void qspinlock_note_use(
    struct qspinlock *lock,
    enum lock_op_flags flags
)
source
bool qspinlock_order_checked(struct qspinlock *lock)
source
void qspinlock_classify(
    struct qspinlock *lock,
    enum lock_op_flags usage,
    const struct lock_chk_site *site
)
source
bool qspinlock_deep_checked(struct qspinlock *lock)
source
void qspinlock_acq_begin(
    struct qspinlock_acq_scope *scope,
    struct qspinlock *lock,
    const struct lock_chk_site *site,
    enum lock_subclass subclass,
    enum lock_op_flags flags
)
source
void qspinlock_acq_commit(struct qspinlock_acq_scope *scope)
source
void qspinlock_acq_abort(struct qspinlock_acq_scope *scope)
source
void qspinlock_rel_begin(
    struct qspinlock_rel_scope *scope,
    struct qspinlock *lock,
    const struct lock_chk_site *site
)
source
void qspinlock_rel_commit(struct qspinlock_rel_scope *scope)
source
void qspinlock_shallow_push(
    struct qspinlock *lock,
    enum irql irql,
    const struct lock_chk_site *site
)
source
void qspinlock_shallow_validate_top(
    struct qspinlock *lock,
    enum irql old,
    const struct lock_chk_site *site
)
source
void qspinlock_shallow_pop(struct qspinlock *lock)
source
bool qspinlock_assert_held_deep(
    struct qspinlock *lock,
    bool want_held,
    const struct lock_chk_site *site
)
source
void qspinlock_init_chk_full(
    struct qspinlock *lock,
    const struct lock_chk_class *class,
    enum lock_chk_flags flags
)
source
cc_warn_unused_result bool qspin_trylock_physical(struct qspinlock *lock)
source
void qspin_lock_slowpath(struct qspinlock *lock, uint32_t val)
source
void qspin_lock_physical(struct qspinlock *lock)
source
void qspin_unlock_physical(struct qspinlock *lock)
source
bool qspin_is_locked(const struct qspinlock *lock)
source
cc_warn_unused_result bool qspin_trylock_raw_full(
    struct qspinlock *lock,
    enum lock_subclass sc,
    const struct lock_chk_site *site
)
source
void qspin_lock_raw_full(
    struct qspinlock *lock,
    enum lock_subclass sc,
    const struct lock_chk_site *site
)
source
void qspin_unlock_raw_full(
    struct qspinlock *lock,
    const struct lock_chk_site *site
)
source
void qspin_unlock_full(
    struct qspinlock *lock,
    enum irql old_irql,
    const struct lock_chk_site *site
)
source
irql qspin_lock_full(
    struct qspinlock *lock,
    enum lock_subclass sc,
    const struct lock_chk_site *site
)
source
irql qspin_lock_high_full(
    struct qspinlock *lock,
    enum lock_subclass sc,
    const struct lock_chk_site *site
)
source
cc_warn_unused_result bool qspin_trylock_full(
    struct qspinlock *lock,
    enum irql *out,
    enum lock_subclass sc,
    const struct lock_chk_site *site
)
source
cc_warn_unused_result bool qspin_trylock_high_full(
    struct qspinlock *lock,
    enum irql *out,
    enum lock_subclass sc,
    const struct lock_chk_site *site
)
source
void qspin_assert_held_full(
    struct qspinlock *lock,
    const struct lock_chk_site *site
)
source
void qspin_assert_not_held_full(
    struct qspinlock *lock,
    const struct lock_chk_site *site
)
source
void qspinlock_guard_assume(struct qspinlock *lock)
source
void qspinlock_guard_exit(struct qspinlock_guard *g)
source
struct qspinlock_guard qspin_guard_enter(struct qspinlock *lock)
source
struct qspinlock_guard qspin_guard_high_enter(struct qspinlock *lock)
source
struct qspinlock_guard qspin_guard_high_subclass_enter(
    struct qspinlock *lock,
    enum lock_subclass sc
)
source
struct qspinlock_guard qspin_guard_subclass_enter(
    struct qspinlock *lock,
    enum lock_subclass sc
)
source
struct lock_chk_lock chk
source
atomic(enum lock_op_flags) irq_usage
source
#define Q_SPIN_LOCKED_OFFSET 0
source

Bit layout of the lock word:

 0 - 7: locked byte (Q_SPIN_LOCKED_VAL = 0x01)  8 : pending bit (Q_SPIN_PENDING_VAL = 0x100)  9 - 10: tail context index 16 - 31: tail CPU ID + 1 (16 bits)

#define Q_SPIN_LOCKED_BITS 8
source
#define Q_SPIN_LOCKED_MASK 0x000000FFU
source
#define Q_SPIN_LOCKED_VAL 0x00000001U
source
#define Q_SPIN_PENDING_OFFSET 8
source
#define Q_SPIN_PENDING_BITS 1
source
#define Q_SPIN_PENDING_MASK 0x00000100U
source
#define Q_SPIN_PENDING_VAL 0x00000100U
source
#define Q_SPIN_LOCKED_PENDING_MASK (Q_SPIN_LOCKED_MASK | Q_SPIN_PENDING_MASK)
source
#define Q_SPIN_TAIL_LVL_OFFSET 9
source
#define Q_SPIN_TAIL_LVL_BITS 2
source
#define Q_SPIN_TAIL_LVL_MASK 0x00000600U
source
#define Q_SPIN_TAIL_CPU_OFFSET 16
source
#define Q_SPIN_TAIL_CPU_BITS 16
source
#define Q_SPIN_TAIL_CPU_MASK 0xFFFF0000U
source
#define Q_SPIN_TAIL_MASK (Q_SPIN_TAIL_LVL_MASK | Q_SPIN_TAIL_CPU_MASK)
source
#define QSPINLOCK_INIT QSPINLOCK_INIT_CHK(NULL, LOCK_CHKD_FULL)
source
#define QSPINLOCK_DEFINE(id)
source
Expansion
#define QSPINLOCK_DEFINE(id) struct qspinlock id = QSPINLOCK_INIT
#define QSPINLOCK_DEFINE_CHK(id, class_, flags_)
source
Expansion
#define QSPINLOCK_DEFINE_CHK(id, class_, flags_) \
    struct qspinlock id = QSPINLOCK_INIT_CHK((class_), (flags_))
#define __QSPINLOCK_SHALLOW_VALUE_INIT
source
Expansion
#define __QSPINLOCK_SHALLOW_VALUE_INIT \
    , .irq_usage = ATOMIC_VAR_INIT(LOCK_OP_IRQ_NONE)
#define __QSPINLOCK_LOCK_CHK_VALUE_INIT(class_, flags_)
source
Expansion
#define __QSPINLOCK_LOCK_CHK_VALUE_INIT(class_, flags_) \
    , .chk = LOCK_CHK_LOCK_VALUE_INIT((class_), (flags_))
#define QSPINLOCK_INIT_CHK(class_, flags_)
source
Expansion
#define QSPINLOCK_INIT_CHK(class_, flags_) \
    ((struct qspinlock) { \
        .val = ATOMIC_VAR_INIT(0) __QSPINLOCK_LOCK_CHK_VALUE_INIT( \
            (class_), (flags_)) __QSPINLOCK_SHALLOW_VALUE_INIT})
#define qspinlock_init_chk(lock_, class_, flags_)
source
Expansion
#define qspinlock_init_chk(lock_, class_, flags_) \
    qspinlock_init_chk_full((lock_), (class_), (flags_))
#define qspinlock_init_auto_internal(lock_, flags_)
source
Expansion
#define qspinlock_init_auto_internal(lock_, flags_) \
    do { \
        static const struct lock_chk_class __auto_class = { \
            .name = #lock_, \
            .file = __RELFILE__, \
            .line = __LINE__, \
        }; \
        qspinlock_init_chk_full((lock_), &__auto_class, (flags_)); \
    } while (0)
#define __QSPINLOCK_SHALLOW_VALUE_INIT
source
#define __QSPINLOCK_LOCK_CHK_VALUE_INIT(class_, flags_)
source
Expansion
#define __QSPINLOCK_LOCK_CHK_VALUE_INIT(class_, flags_)
#define QSPINLOCK_INIT_CHK(class_, flags_)
source
Expansion
#define QSPINLOCK_INIT_CHK(class_, flags_) \
    ((struct qspinlock) {.val = ATOMIC_VAR_INIT(0)})
#define qspinlock_init_chk(lock_, class_, flags_)
source
Expansion
#define qspinlock_init_chk(lock_, class_, flags_) \
    qspinlock_init_chk_full((lock_), NULL, LOCK_UNCHKD)
#define qspinlock_init_auto_internal(lock_, flags_)
source
Expansion
#define qspinlock_init_auto_internal(lock_, flags_) \
    qspinlock_init_chk_full((lock_), NULL, LOCK_UNCHKD)
#define qspinlock_init_1(lock_)
source
Expansion
#define qspinlock_init_1(lock_) qspinlock_init_2(lock_, LOCK_CHKD_FULL)
#define qspinlock_init_2(lock_, flags_)
source
Expansion
#define qspinlock_init_2(lock_, flags_) \
    qspinlock_init_auto_internal((lock_), (flags_))
#define qspinlock_init(...)
source
Expansion
#define qspinlock_init(...) PP_CALL(qspinlock_init, __VA_ARGS__)
#define qspin_init(...)
source
Expansion
#define qspin_init(...) qspinlock_init(__VA_ARGS__)
#define qspin_init_chk(...)
source
Expansion
#define qspin_init_chk(...) qspinlock_init_chk(__VA_ARGS__)
#define QSPINLOCK_ASSERT_HELD_RAW(l)
source

Same deal as SPINLOCK_ASSERT_HELD_RAW, just checks the bit, but that doesn’t say anything about thread ownership

Expansion
#define QSPINLOCK_ASSERT_HELD_RAW(l) \
    enforce(qspin_is_locked(l), "qspinlock not locked")
#define qspin_lock(lock_)
source
Expansion
#define qspin_lock(lock_) \
    qspin_lock_full((lock_), LOCK_SUBCLASS_PRIMARY, LOCK_CHK_SITE_HERE())
#define qspin_lock_subclass(lock_, subclass_)
source
Expansion
#define qspin_lock_subclass(lock_, subclass_) \
    qspin_lock_full((lock_), (subclass_), LOCK_CHK_SITE_HERE())
#define qspin_lock_high(lock_)
source
#define qspin_lock_high_subclass(lock_, subclass_)
source
Expansion
#define qspin_lock_high_subclass(lock_, subclass_) \
    qspin_lock_high_full((lock_), (subclass_), LOCK_CHK_SITE_HERE())
#define qspin_trylock(lock_, out_)
source
Expansion
#define qspin_trylock(lock_, out_) \
    qspin_trylock_full((lock_), (out_), LOCK_SUBCLASS_PRIMARY, \
                       LOCK_CHK_SITE_HERE())
#define qspin_trylock_subclass(lock_, out_, subclass_)
source
Expansion
#define qspin_trylock_subclass(lock_, out_, subclass_) \
    qspin_trylock_full((lock_), (out_), (subclass_), LOCK_CHK_SITE_HERE())
#define qspin_trylock_high(lock_, out_)
source
Expansion
#define qspin_trylock_high(lock_, out_) \
    qspin_trylock_high_full((lock_), (out_), LOCK_SUBCLASS_PRIMARY, \
                            LOCK_CHK_SITE_HERE())
#define qspin_trylock_high_subclass(lock_, out_, subclass_)
source
Expansion
#define qspin_trylock_high_subclass(lock_, out_, subclass_) \
    qspin_trylock_high_full((lock_), (out_), (subclass_), LOCK_CHK_SITE_HERE())
#define qspin_unlock(lock_, old_)
source
Expansion
#define qspin_unlock(lock_, old_) \
    qspin_unlock_full((lock_), (old_), LOCK_CHK_SITE_HERE())
#define qspin_unlock_irq_restore(lock_, old_)
source
Expansion
#define qspin_unlock_irq_restore(lock_, old_) \
    qspin_unlock_full((lock_), (old_), LOCK_CHK_SITE_HERE())
#define qspin_lock_raw(lock_)
source
#define qspin_lock_raw_subclass(lock_, subclass_)
source
Expansion
#define qspin_lock_raw_subclass(lock_, subclass_) \
    qspin_lock_raw_full((lock_), (subclass_), LOCK_CHK_SITE_HERE())
#define qspin_trylock_raw(lock_)
source
#define qspin_trylock_raw_subclass(lock_, subclass_)
source
Expansion
#define qspin_trylock_raw_subclass(lock_, subclass_) \
    qspin_trylock_raw_full((lock_), (subclass_), LOCK_CHK_SITE_HERE())
#define qspin_unlock_raw(lock_)
source
Expansion
#define qspin_unlock_raw(lock_) \
    qspin_unlock_raw_full((lock_), LOCK_CHK_SITE_HERE())
#define QSPINLOCK_ASSERT_HELD(l)
source
#define QSPINLOCK_ASSERT_NOT_HELD(l)
source
#define qspin_guard(lock_)
source
Expansion
#define qspin_guard(lock_) \
    cc_cleanup(qspinlock_guard_exit) struct qspinlock_guard PP_CONCAT( \
        qspin_guard_, __COUNTER__) = \
        (qspinlock_guard_assume(lock_), qspin_guard_enter(lock_))
#define qspin_guard_high(lock_)
source
Expansion
#define qspin_guard_high(lock_) \
    cc_cleanup(qspinlock_guard_exit) struct qspinlock_guard PP_CONCAT( \
        qspin_guard_high_, __COUNTER__) = \
        (qspinlock_guard_assume(lock_), qspin_guard_high_enter(lock_))
#define qspin_guard_subclass(lock_, subclass_)
source
Expansion
#define qspin_guard_subclass(lock_, subclass_) \
    cc_cleanup(qspinlock_guard_exit) struct qspinlock_guard PP_CONCAT( \
        qspin_guard_, __COUNTER__) = \
        (qspinlock_guard_assume(lock_), \
         qspin_guard_subclass_enter((lock_), (subclass_)))
#define qspin_guard_high_subclass(lock_, subclass_)
source
Expansion
#define qspin_guard_high_subclass(lock_, subclass_) \
    cc_cleanup(qspinlock_guard_exit) struct qspinlock_guard PP_CONCAT( \
        qspin_guard_high_, __COUNTER__) = \
        (qspinlock_guard_assume(lock_), \
         qspin_guard_high_subclass_enter((lock_), (subclass_)))