write_seqcount_latch_begin(9)
β¨ write_seqcount_latch_begin(9) β¨
okay so this is a page straight out of the Kernel API Manual, and bestie, it's about write_seqcount_latch_begin(9) β the little function that flips your readers over to the odd copy so you can go mess with the even one π
πΈ NAME πΈ
write_seqcount_latch_begin β redirect latch readers to odd copy
Literally what it says. It's giving "traffic cop but for readers" π
π¦ SYNOPSIS π¦
void write_seqcount_latch_begin (seqcount_latch_t *s );
π ARGUMENTS π
sβ Pointer toseqcount_latch_t. Yep, that's the whole thing. Just hand it the latch and it does its thing π
π DESCRIPTION π
So the latch technique is a multiversion concurrency control method β say that five times fast β and what it does is let queries happen during non-atomic modifications. Slay.
But quick vibe check: if you can guarantee queries never interrupt the modification β like, the concurrency is strictly between CPUs β you most likely do not need this. fr fr, don't over-engineer.
Here's the tea β: traditional RCU/lockless data structures rely on atomic modifications to make sure queries see either the old state or the new state. The latch lets you pull off the same thing for non-atomic updates. The trade-off? You're doubling the storage cost π β you have to keep two copies of the entire data structure. Two. Copies. Periodt.
Very simply put: we first modify one copy, then the other. That way there's always one copy chilling in a stable state, ready to give us an answer. Iconic behaviour, honestly.
The basic form is a data structure like:
struct latch_struct {
seqcount_latch_t seq;
struct data_struct data[2];
};
Where a modification β which is assumed to be externally serialized β does the following:
void latch_modify(struct latch_struct *latch, ...)
{
write_seqcount_latch_begin(latch->seq);
modify(latch->data[0], ...);
write_seqcount_latch(latch->seq);
modify(latch->data[1], ...);
write_seqcount_latch_end(latch->seq);
}
And the query has a form like:
struct entry *latch_query(struct latch_struct *latch, ...)
{
struct entry *entry;
unsigned seq, idx;
do {
seq = read_seqcount_latch(latch->seq);
idx = seq & 0x01;
entry = data_query(latch->data[idx], ...);
// This includes needed smp_rmb
} while (read_seqcount_latch_retry(latch->seq, seq));
return entry;
}
So during the modification, queries get redirected to data[1] first. Then we modify data[0]. When that's done, we redirect queries back to data[0] and then we can modify data[1]. See the dance? π§ It's a whole choreography and it eats every time.
π NOTE π
The non-requirement for atomic modifications does _NOT_ β that's a big NOT, underline it, highlight it β include the publishing of new entries in the case where data is a dynamic data structure. Don't come for me.
An iteration might start in data[0] and get suspended long enough to miss an entire modification sequence, and once it resumes it might observe the new entry. π yeah. awkward.
NOTE2: When data is a dynamic data structure, one should use regular RCU patterns to manage the lifetimes of the objects within. No cap, do this.
β SEE ALSO β
Kernel file ./include/linux/seqlock.h β and the whole extended friend group π«Ά:
seqcount_init(9)SEQCNT_ZERO(9)__read_seqcount_begin(9)raw_read_seqcount_begin(9)read_seqcount_begin(9)raw_read_seqcount(9)raw_seqcount_try_begin(9)raw_seqcount_begin(9)__read_seqcount_retry(9)read_seqcount_retry(9)raw_write_seqcount_begin(9)raw_write_seqcount_end(9)write_seqcount_begin_nested(9)write_seqcount_begin(9)write_seqcount_end(9)raw_write_seqcount_barrier(9)write_seqcount_invalidate(9)SEQCNT_LATCH_ZERO(9)seqcount_latch_init(9)raw_read_seqcount_latch(9)read_seqcount_latch(9)raw_read_seqcount_latch_retry(9)read_seqcount_latch_retry(9)raw_write_seqcount_latch(9)write_seqcount_latch(9)write_seqcount_latch_end(9)seqlock_init(9)DEFINE_SEQLOCK(9)read_seqbegin(9)read_seqretry(9)write_seqlock(9)write_sequnlock(9)write_seqlock_bh(9)write_sequnlock_bh(9)write_seqlock_irq(9)write_sequnlock_irq(9)write_seqlock_irqsave(9)write_sequnlock_irqrestore(9)read_seqlock_excl(9)read_sequnlock_excl(9)read_seqlock_excl_bh(9)read_sequnlock_excl_bh(9)read_seqlock_excl_irq(9)read_sequnlock_excl_irq(9)read_seqlock_excl_irqsave(9)read_sequnlock_excl_irqrestore(9)read_seqbegin_or_lock(9)need_seqretry(9)done_seqretry(9)read_seqbegin_or_lock_irqsave(9)done_seqretry_irqrestore(9)scoped_seqlock_read(9)
and that's the whole page, bestie π it lives in ./include/linux, dated October 2026, and yes the footer says write_seqcount_latch_begin(9) again because the kernel loves a callback. go forth and redirect those readers π¦β¨
π¦ where this page comes from
- nixpkgs unstable: linux-manual 7.3.1
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms