Skip to content

Sequence Lock

include/sync/seqlock.h View source View on GitHub
struct seqcount {
    _Atomic uint32_t  sequence;
};
struct seqlock {
    struct seqcount  seqcount;
    struct spinlock  lock;
};
typedef struct seqcount seqcount_t;
typedef struct seqlock seqlock_t;
void seqcount_init(struct seqcount *s);
uint32_t seqcount_read_raw(const struct seqcount *s);
uint32_t seqcount_begin_read_raw(const struct seqcount *s);
uint32_t seqcount_begin_read(const struct seqcount *s);
bool seqcount_read_retry(const struct seqcount *s, uint32_t start);
void seqcount_begin_write(struct seqcount *s);
void seqcount_end_write(struct seqcount *s);
void seqlock_init_chk_internal(struct seqlock *sl, const struct lock_chk_class *class, enum lock_chk_flags flags);
uint32_t seq_begin_read(const struct seqlock *sl);
bool seq_read_retry(const struct seqlock *sl, uint32_t start);
uint32_t seq_begin_read_raw(const struct seqlock *sl);
uint32_t seq_read_raw(const struct seqlock *sl);
enum irql seq_write_lock(struct seqlock *sl);
enum irql seq_write_lock_irq_disable(struct seqlock *sl);
void seq_write_unlock(struct seqlock *sl, enum irql old);
void seq_write_lock_raw(struct seqlock *sl);
void seq_write_unlock_raw(struct seqlock *sl);
bool seq_try_write_lock(struct seqlock *sl, enum irql *out);
bool seq_try_write_lock_irq_disable(struct seqlock *sl, enum irql *out);
bool seq_try_write_lock_raw(struct seqlock *sl);
bool seqlock_is_writing(const struct seqlock *sl);
bool seqlock_held(const struct seqlock *sl);
#define SEQCOUNT_INIT \
    (struct seqcount) { \
        .sequence = ATOMIC_VAR_INIT(0) \
    }
#define SEQLOCK_INIT_CHK(class_, flags_) \
    (struct seqlock) { \
        .seqcount = SEQCOUNT_INIT, \
        .lock = SPINLOCK_INIT_CHK((class_), (flags_)) \
    }
#define SEQLOCK_INIT SEQLOCK_INIT_CHK(NULL, LOCK_CHKD_FULL)
#define SEQLOCK_DEFINE(id) struct seqlock id = SEQLOCK_INIT
#define SEQLOCK_DEFINE_CHK(id, class_, flags_) \
    struct seqlock id = SEQLOCK_INIT_CHK((class_), (flags_))
#define seqlock_init_chk(sl_, class_, flags_) \
    seqlock_init_chk_internal((sl_), (class_), (flags_))
#define seqlock_init_auto_internal(sl_, flags_) \
    do { \
        static const struct lock_chk_class __auto_class = { \
            .name = #sl_, \
            .file = __RELFILE__, \
            .line = __LINE__, \
        }; \
        seqlock_init_chk_internal((sl_), &__auto_class, (flags_)); \
    } while (0)
#define seqlock_init_chk(sl_, class_, flags_) \
    seqlock_init_chk_internal((sl_), NULL, LOCK_UNCHKD)
#define seqlock_init_auto_internal(sl_, flags_) \
    seqlock_init_chk_internal((sl_), NULL, LOCK_UNCHKD)
#define seqlock_init_1(sl_) seqlock_init_auto_internal((sl_), LOCK_CHKD_FULL)
#define seqlock_init_2(sl_, flags_) seqlock_init_auto_internal((sl_), (flags_))
#define seqlock_init(...) \
    _DISPATCH(seqlock_init, PP_NARG(__VA_ARGS__))(__VA_ARGS__)
#define SEQLOCK_ASSERT_HELD(sl) kassert(seqlock_held(sl))