Sequence Lock
include/sync/seqlock.h View source View on GitHubThe naming here is rather… unpleasant, so it’s worth specifying upfront:
seqcount_ is for all the struct seqcount functions, seq_ and seqlock_ are for the struct seqlock functions, we keep it this way so that function signatures don’t explode in length, and to mirror the general naming conventions of the lock primitives with lock in their name (see spinlock.h, rwlock.h)
(begin_|end_)(read|write)(_raw)(_high)(_retry)
is the syntax ordering, broadly
Structs
Section titled “Structs”seqcount
Section titled “seqcount” struct seqcount (1 field) source
Sequence counters for lock free reader synchronization with serialized writers
Odd sequence indicates an in progress write, even count indicates quiescent data.
the thread API and thread.c uses what is effectively a sequence counter, just not with this API. someday we can change it over
atomic_uint32_t sequence seqlock
Section titled “seqlock” struct seqlock (2 fields) source
seqlock_write_guard
Section titled “seqlock_write_guard”seqlock_write_raw_guard
Section titled “seqlock_write_raw_guard”Type Aliases
Section titled “Type Aliases”seqcount_t
Section titled “seqcount_t”seqlock_t
Section titled “seqlock_t”Functions
Section titled “Functions”seqcount_init
Section titled “seqcount_init”seqcount_read_raw
Section titled “seqcount_read_raw”seqcount_begin_read_raw
Section titled “seqcount_begin_read_raw”seqcount_begin_read
Section titled “seqcount_begin_read”Wait for any active writer to complete and return the sequence with acquire barrier
seqcount_read_retry
Section titled “seqcount_read_retry”Check for change since start
seqcount_begin_write
Section titled “seqcount_begin_write”even to odd with wmb
the separate rlx load and store here is intentional: atomic_fetch_add is RMW, and unneeded when there is only one writer
seqcount_end_write
Section titled “seqcount_end_write”seqlock_init_chk_full
Section titled “seqlock_init_chk_full”void seqlock_init_chk_full(
struct seqlock *sl,
const struct lock_chk_class *class,
enum lock_chk_flags flags
) source seq_begin_read
Section titled “seq_begin_read”seq_read_retry
Section titled “seq_read_retry”seq_begin_read_raw
Section titled “seq_begin_read_raw”seq_read_raw
Section titled “seq_read_raw”seq_write_lock
Section titled “seq_write_lock”seq_write_lock_high
Section titled “seq_write_lock_high”seq_write_unlock
Section titled “seq_write_unlock”seq_write_lock_raw
Section titled “seq_write_lock_raw”seq_write_unlock_raw
Section titled “seq_write_unlock_raw”seq_try_write_lock
Section titled “seq_try_write_lock”cc_warn_unused_result bool seq_try_write_lock(
struct seqlock *sl,
enum irql *out
) source Trylock
seq_try_write_lock_high
Section titled “seq_try_write_lock_high”cc_warn_unused_result bool seq_try_write_lock_high(
struct seqlock *sl,
enum irql *out
) source seq_try_write_lock_raw
Section titled “seq_try_write_lock_raw”cc_warn_unused_result bool seq_try_write_lock_raw(struct seqlock *sl) source seqlock_is_writing
Section titled “seqlock_is_writing”seqlock_held
Section titled “seqlock_held”seqcount_write_guard_exit
Section titled “seqcount_write_guard_exit”seqcount_write_guard_enter
Section titled “seqcount_write_guard_enter”seqlock_write_guard_assume
Section titled “seqlock_write_guard_assume”seqlock_write_guard_exit
Section titled “seqlock_write_guard_exit”void seqlock_write_guard_exit(struct seqlock_write_guard *g) source seqlock_write_guard_enter
Section titled “seqlock_write_guard_enter”struct seqlock_write_guard seqlock_write_guard_enter(struct seqlock *sl) source seqlock_write_high_guard_enter
Section titled “seqlock_write_high_guard_enter”struct seqlock_write_guard seqlock_write_high_guard_enter(struct seqlock *sl) source seqlock_write_raw_guard_exit
Section titled “seqlock_write_raw_guard_exit”void seqlock_write_raw_guard_exit(struct seqlock_write_raw_guard *g) source seqlock_write_raw_guard_enter
Section titled “seqlock_write_raw_guard_enter”struct seqlock_write_raw_guard seqlock_write_raw_guard_enter(struct seqlock *sl) source Macros
Section titled “Macros”SEQCOUNT_INIT
Section titled “SEQCOUNT_INIT”#define SEQCOUNT_INIT source Expansion
#define SEQCOUNT_INIT \
(struct seqcount) { \
.sequence = ATOMIC_VAR_INIT(0) \
} SEQLOCK_INIT_CHK
Section titled “SEQLOCK_INIT_CHK”#define SEQLOCK_INIT_CHK(class_, flags_) source Expansion
#define SEQLOCK_INIT_CHK(class_, flags_) \
(struct seqlock) { \
.seqcount = SEQCOUNT_INIT, \
.lock = SPINLOCK_INIT_CHK((class_), (flags_)) \
} SEQLOCK_INIT
Section titled “SEQLOCK_INIT”#define SEQLOCK_INIT SEQLOCK_INIT_CHK(NULL, LOCK_CHKD_FULL) source SEQLOCK_DEFINE
Section titled “SEQLOCK_DEFINE”#define SEQLOCK_DEFINE(id) source Expansion
#define SEQLOCK_DEFINE(id) struct seqlock id = SEQLOCK_INIT SEQLOCK_DEFINE_CHK
Section titled “SEQLOCK_DEFINE_CHK”#define SEQLOCK_DEFINE_CHK(id, class_, flags_) source Expansion
#define SEQLOCK_DEFINE_CHK(id, class_, flags_) \
struct seqlock id = SEQLOCK_INIT_CHK((class_), (flags_)) seqlock_init_chk
Section titled “seqlock_init_chk”#define seqlock_init_chk(sl_, class_, flags_) source Expansion
#define seqlock_init_chk(sl_, class_, flags_) \
seqlock_init_chk_full((sl_), (class_), (flags_)) seqlock_init_auto_internal
Section titled “seqlock_init_auto_internal”#define seqlock_init_auto_internal(sl_, flags_) source Expansion
#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_full((sl_), &__auto_class, (flags_)); \
} while (0) seqlock_init_chk
Section titled “seqlock_init_chk”#define seqlock_init_chk(sl_, class_, flags_) source Expansion
#define seqlock_init_chk(sl_, class_, flags_) \
seqlock_init_chk_full((sl_), NULL, LOCK_UNCHKD) seqlock_init_auto_internal
Section titled “seqlock_init_auto_internal”#define seqlock_init_auto_internal(sl_, flags_) source Expansion
#define seqlock_init_auto_internal(sl_, flags_) \
seqlock_init_chk_full((sl_), NULL, LOCK_UNCHKD) seqlock_init_1
Section titled “seqlock_init_1”#define seqlock_init_1(sl_) source Expansion
#define seqlock_init_1(sl_) seqlock_init_2(sl_, LOCK_CHKD_FULL) seqlock_init_2
Section titled “seqlock_init_2”#define seqlock_init_2(sl_, flags_) source Expansion
#define seqlock_init_2(sl_, flags_) seqlock_init_auto_internal((sl_), (flags_)) seqlock_init
Section titled “seqlock_init”#define seqlock_init(...) source Expansion
#define seqlock_init(...) PP_CALL(seqlock_init, __VA_ARGS__) SEQLOCK_ASSERT_HELD
Section titled “SEQLOCK_ASSERT_HELD”#define SEQLOCK_ASSERT_HELD(sl) source Expansion
#define SEQLOCK_ASSERT_HELD(sl) enforce(seqlock_held(sl)) seqcount_write_guard
Section titled “seqcount_write_guard”#define seqcount_write_guard(s_) source Expansion
#define seqcount_write_guard(s_) \
cc_cleanup(seqcount_write_guard_exit) struct seqcount *PP_CONCAT( \
seqc_guard_, __COUNTER__) = seqcount_write_guard_enter(s_) seq_write_guard
Section titled “seq_write_guard”#define seq_write_guard(sl_) source Expansion
#define seq_write_guard(sl_) \
cc_cleanup(seqlock_write_guard_exit) struct seqlock_write_guard PP_CONCAT( \
seq_wguard_, __COUNTER__) = \
(seqlock_write_guard_assume(sl_), seqlock_write_guard_enter(sl_)) seq_write_guard_high
Section titled “seq_write_guard_high”#define seq_write_guard_high(sl_) source Expansion
#define seq_write_guard_high(sl_) \
cc_cleanup(seqlock_write_guard_exit) struct seqlock_write_guard PP_CONCAT( \
seq_wguard_high_, __COUNTER__) = \
(seqlock_write_guard_assume(sl_), seqlock_write_high_guard_enter(sl_)) seq_write_guard_raw
Section titled “seq_write_guard_raw”#define seq_write_guard_raw(sl_) source Expansion
#define seq_write_guard_raw(sl_) \
cc_cleanup(seqlock_write_raw_guard_exit) struct seqlock_write_raw_guard \
PP_CONCAT(seq_wguard_raw_, __COUNTER__) = \
(seqlock_write_guard_assume(sl_), seqlock_write_raw_guard_enter(sl_))