Sequence counters and sequential locks¶
Introduction¶
Sequence counters are a reader-writer consistency mechanism with lockless readers (read-only retry loops), and no writer starvation. They are used for data that’s rarely written to (e.g. system time), where the reader wants a consistent set of information and is willing to retry if that information changes.
A data set is consistent when the sequence count at the beginning of the read side critical section is even and the same sequence count value is read again at the end of the critical section. The data in the set must be copied out inside the read side critical section. If the sequence count has changed between the start and the end of the critical section, the reader must retry.
Writers increment the sequence count at the start and the end of their critical section. After starting the critical section the sequence count is odd and indicates to the readers that an update is in progress. At the end of the write side critical section the sequence count becomes even again which lets readers make progress.
A sequence counter write side critical section must never be preempted or interrupted by read side sections. Otherwise the reader will spin for the entire scheduler tick due to the odd sequence count value and the interrupted writer. If that reader belongs to a real-time scheduling class, it can spin forever and the kernel will livelock.
This mechanism cannot be used if the protected data contains pointers, as the writer can invalidate a pointer that the reader is following.
Sequence counters (seqcount_t
)¶
This is the the raw counting mechanism, which does not protect against multiple writers. Write side critical sections must thus be serialized by an external lock.
If the write serialization primitive is not implicitly disabling preemption, preemption must be explicitly disabled before entering the write side section. If the read section can be invoked from hardirq or softirq contexts, interrupts or bottom halves must also be respectively disabled before entering the write section.
If the write serialization mechanism is one of the common kernel locking primitives, use sequence counters with associated locks instead. If it’s desired to automatically handle the sequence counter writer serialization and non-preemptibility requirements, use a sequential lock.
Initialization:
/* dynamic */
seqcount_t foo_seqcount;
seqcount_init(&foo_seqcount);
/* static */
static seqcount_t foo_seqcount = SEQCNT_ZERO(foo_seqcount);
/* C99 struct init */
struct {
.seq = SEQCNT_ZERO(foo.seq),
} foo;
Write path:
/* Serialized context with disabled preemption */
write_seqcount_begin(&foo_seqcount);
/* ... [[write-side critical section]] ... */
write_seqcount_end(&foo_seqcount);
Read path:
do {
seq = read_seqcount_begin(&foo_seqcount);
/* ... [[read-side critical section]] ... */
} while (read_seqcount_retry(&foo_seqcount, seq));
Sequence counters with associated locks (seqcount_LOCKTYPE_t
)¶
As earlier discussed, seqcount write side critical sections must be serialized and non-preemptible. This variant of sequence counters associate the lock used for writer serialization at the seqcount initialization time. This enables lockdep to validate that the write side critical section is properly serialized.
This lock association is a NOOP if lockdep is disabled and has neither storage nor runtime overhead. If lockdep is enabled, the lock pointer is stored in struct seqcount and lockdep’s “lock is held” assertions are injected at the beginning of the write side critical section to validate that it is properly protected.
For lock types which do not implicitly disable preemption, preemption protection is enforced in the write side function.
The following seqcounts with associated locks are defined:
seqcount_spinlock_t
seqcount_raw_spinlock_t
seqcount_rwlock_t
seqcount_mutex_t
seqcount_ww_mutex_t
The plain seqcount read and write APIs branch out to the specific seqcount_LOCKTYPE_t implementation at compile-time. This avoids kernel API explosion per each new seqcount LOCKTYPE.
Initialization (replace “LOCKTYPE” with one of the supported locks):
/* dynamic */
seqcount_LOCKTYPE_t foo_seqcount;
seqcount_LOCKTYPE_init(&foo_seqcount, &lock);
/* static */
static seqcount_LOCKTYPE_t foo_seqcount =
SEQCNT_LOCKTYPE_ZERO(foo_seqcount, &lock);
/* C99 struct init */
struct {
.seq = SEQCNT_LOCKTYPE_ZERO(foo.seq, &lock),
} foo;
Write path: same as in plain seqcount_t, while running from a context with the associated LOCKTYPE lock acquired.
Read path: same as in plain seqcount_t.
Sequential locks (seqlock_t
)¶
This contains the sequence counting mechanism earlier discussed, plus an embedded spinlock for writer serialization and non-preemptibility.
If the read side section can be invoked from hardirq or softirq context, use the write side function variants which disable interrupts or bottom halves respectively.
Initialization:
/* dynamic */
seqlock_t foo_seqlock;
seqlock_init(&foo_seqlock);
/* static */
static DEFINE_SEQLOCK(foo_seqlock);
/* C99 struct init */
struct {
.seql = __SEQLOCK_UNLOCKED(foo.seql)
} foo;
Write path:
write_seqlock(&foo_seqlock);
/* ... [[write-side critical section]] ... */
write_sequnlock(&foo_seqlock);
Read path, three categories:
Normal Sequence readers which never block a writer but they must retry if a writer is in progress by detecting change in the sequence number. Writers do not wait for a sequence reader.
do { seq = read_seqbegin(&foo_seqlock); /* ... [[read-side critical section]] ... */ } while (read_seqretry(&foo_seqlock, seq));
Locking readers which will wait if a writer or another locking reader is in progress. A locking reader in progress will also block a writer from entering its critical section. This read lock is exclusive. Unlike rwlock_t, only one locking reader can acquire it.
read_seqlock_excl(&foo_seqlock); /* ... [[read-side critical section]] ... */ read_sequnlock_excl(&foo_seqlock);
Conditional lockless reader (as in 1), or locking reader (as in 2), according to a passed marker. This is used to avoid lockless readers starvation (too much retry loops) in case of a sharp spike in write activity. First, a lockless read is tried (even marker passed). If that trial fails (odd sequence counter is returned, which is used as the next iteration marker), the lockless read is transformed to a full locking read and no retry loop is necessary.
/* marker; even initialization */ int seq = 0; do { read_seqbegin_or_lock(&foo_seqlock, &seq); /* ... [[read-side critical section]] ... */ } while (need_seqretry(&foo_seqlock, seq)); done_seqretry(&foo_seqlock, seq);
API documentation¶
-
seqcount_init ( s)
runtime initializer for seqcount_t
Parameters
s
Pointer to the
typedef seqcount_t
instance
-
SEQCNT_ZERO ( name)
static initializer for seqcount_t
Parameters
name
Name of the
typedef seqcount_t
instance
-
__read_seqcount_begin ( s)
begin a seq-read critical section (without barrier)
Parameters
s
Pointer to
typedef seqcount_t
or any of the seqcount_locktype_t variants
Return
count to be passed to read_seqcount_retry
__read_seqcount_begin is like read_seqcount_begin, but has no smp_rmb() barrier. Callers should ensure that smp_rmb() or equivalent ordering is provided before actually loading any of the variables that are to be protected in this critical section.
Use carefully, only in critical code, and comment how the barrier is provided.
-
raw_read_seqcount ( s)
Read the raw seqcount
Parameters
s
Pointer to
typedef seqcount_t
or any of the seqcount_locktype_t variants
Return
count to be passed to read_seqcount_retry
raw_read_seqcount opens a read critical section of the given seqcount_t, without any lockdep checks and without checking or masking the sequence counter LSB. Calling code is responsible for handling that.
-
raw_read_seqcount_begin ( s)
start seq-read critical section w/o lockdep
Parameters
s
Pointer to
typedef seqcount_t
or any of the seqcount_locktype_t variants
Return
count to be passed to read_seqcount_retry
raw_read_seqcount_begin opens a read critical section of the given seqcount_t, but without any lockdep checking. Validity of the read section must be checked with read_seqcount_retry().
-
read_seqcount_begin ( s)
begin a seq-read critical section
Parameters
s
pointer to
typedef seqcount_t
or any of the seqcount_locktype_t variants
Return
count to be passed to read_seqcount_retry
read_seqcount_begin opens a read critical section of the given seqcount_t. Validity of the read section must be checked with read_seqcount_retry().
-
raw_seqcount_begin ( s)
begin a seq-read critical section
Parameters
s
pointer to
typedef seqcount_t
or any of the seqcount_locktype_t variants
Return
count to be passed to read_seqcount_retry
raw_seqcount_begin opens a read critical section of the given seqcount_t. Validity of the critical section is tested by checking read_seqcount_retry function.
Unlike read_seqcount_begin(), this function will not wait for the count to stabilize. If a writer is active when we begin, we will fail the read_seqcount_retry() instead of stabilizing at the beginning of the critical section.
-
__read_seqcount_retry ( s, start)
end a seq-read critical section (without barrier)
Parameters
s
pointer to
typedef seqcount_t
or any of the seqcount_locktype_t variantsstart
count, from read_seqcount_begin
Return
1 if retry is required, else 0
__read_seqcount_retry is like read_seqcount_retry, but has no smp_rmb() barrier. Callers should ensure that smp_rmb() or equivalent ordering is provided before actually loading any of the variables that are to be protected in this critical section.
Use carefully, only in critical code, and comment how the barrier is provided.
-
read_seqcount_retry ( s, start)
end a seq-read critical section
Parameters
s
pointer to
typedef seqcount_t
or any of the seqcount_locktype_t variantsstart
count, from read_seqcount_begin
Return
1 if retry is required, else 0
read_seqcount_retry closes a read critical section of given seqcount_t. If the critical section was invalid, it must be ignored (and typically retried).
-
raw_write_seqcount_barrier ( s)
do a seq write barrier
Parameters
s
Pointer to
typedef seqcount_t
or any of the seqcount_locktype_t variants
Description
This can be used to provide an ordering guarantee instead of the usual consistency guarantee. It is one wmb cheaper, because we can collapse the two back-to-back wmb()s:
seqcount_t seq;
bool X = true, Y = false;
void read(void)
{
bool x, y;
do {
int s = read_seqcount_begin(&seq);
x = X; y = Y;
} while (read_seqcount_retry(&seq, s));
BUG_ON(!x && !y);
}
void write(void)
{
Y = true;
raw_write_seqcount_barrier(seq);
X = false;
}
-
raw_read_seqcount_latch ( s)
pick even or odd seqcount latch data copy
Parameters
s
pointer to
typedef seqcount_t
or any of the seqcount_locktype_t variants
Description
Use seqcount latching to switch between two storage places with sequence protection to allow interruptible, preemptible, writer sections.
Check raw_write_seqcount_latch() for more details and a full reader and writer usage example.
Return
sequence counter. Use the lowest bit as index for picking which data copy to read. Full counter must then be checked with read_seqcount_retry().
-
raw_write_seqcount_latch ( s)
redirect readers to even/odd copy
Parameters
s
pointer to
typedef seqcount_t
or any of the seqcount_locktype_t variants
Description
The latch technique is a multiversion concurrency control method that allows queries during non-atomic modifications. If you can guarantee queries never interrupt the modification – e.g. the concurrency is strictly between CPUs – you most likely do not need this.
Where the traditional RCU/lockless data structures rely on atomic modifications to ensure queries observe either the old or the new state the latch allows the same for non-atomic updates. The trade-off is doubling the cost of storage; we have to maintain two copies of the entire data structure.
Very simply put: we first modify one copy and then the other. This ensures there is always one copy in a stable state, ready to give us an answer.
The basic form is a data structure like:
struct latch_struct {
seqcount_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, ...)
{
smp_wmb(); // Ensure that the last data[1] update is visible
latch->seq++;
smp_wmb(); // Ensure that the seqcount update is visible
modify(latch->data[0], ...);
smp_wmb(); // Ensure that the data[0] update is visible
latch->seq++;
smp_wmb(); // Ensure that the seqcount update is visible
modify(latch->data[1], ...);
}
The query will have a form like:
struct entry *latch_query(struct latch_struct *latch, ...)
{
struct entry *entry;
unsigned seq, idx;
do {
seq = raw_read_seqcount_latch(&latch->seq);
idx = seq & 0x01;
entry = data_query(latch->data[idx], ...);
// read_seqcount_retry() includes necessary smp_rmb()
} while (read_seqcount_retry(&latch->seq, seq);
return entry;
}
So during the modification, queries are first redirected to data[1]. Then we modify data[0]. When that is complete, we redirect queries back to data[0] and we can modify data[1].
NOTE
The non-requirement for atomic modifications does _NOT_ include the publishing of new entries in the case where data is a dynamic data structure.
An iteration might start in data[0] and get suspended long enough to miss an entire modification sequence, once it resumes it might observe the new entry.
When data is a dynamic data structure; one should use regular RCU patterns to manage the lifetimes of the objects within.
-
write_seqcount_begin ( s)
start a seqcount write-side critical section
Parameters
s
Pointer to
typedef seqcount_t
Description
write_seqcount_begin opens a write-side critical section of the given seqcount. Seqcount write-side critical sections must be externally serialized and non-preemptible.
-
write_seqcount_end ( s)
end a seqcount write-side critical section
Parameters
s
Pointer to
typedef seqcount_t
Description
The write section must’ve been opened with write_seqcount_begin().
-
write_seqcount_invalidate ( s)
invalidate in-progress read-side seq operations
Parameters
s
Pointer to
typedef seqcount_t
or any of the seqcount_locktype_t variants
Description
After write_seqcount_invalidate, no read-side seq operations will complete successfully and see data older than this.
-
typedef seqcount_spinlock_t
sequence count with spinlock associated
Description
A plain sequence counter with external writer synchronization by a spinlock. The spinlock is associated to the sequence count in the static initializer or init function. This enables lockdep to validate that the write side critical section is properly serialized.
-
SEQCNT_SPINLOCK_ZERO ( name, lock)
static initializer for seqcount_spinlock_t
Parameters
name
Name of the
typedef seqcount_spinlock_t
instancelock
Pointer to the associated spinlock
-
seqcount_spinlock_init ( s, lock)
runtime initializer for seqcount_spinlock_t
Parameters
s
Pointer to the
typedef seqcount_spinlock_t
instancelock
Pointer to the associated spinlock
-
typedef seqcount_raw_spinlock_t
sequence count with raw spinlock associated
Description
A plain sequence counter with external writer synchronization by a raw spinlock. The raw spinlock is associated to the sequence count in the static initializer or init function. This enables lockdep to validate that the write side critical section is properly serialized.
-
SEQCNT_RAW_SPINLOCK_ZERO ( name, lock)
static initializer for seqcount_raw_spinlock_t
Parameters
name
Name of the
typedef seqcount_raw_spinlock_t
instancelock
Pointer to the associated raw_spinlock
-
seqcount_raw_spinlock_init ( s, lock)
runtime initializer for seqcount_raw_spinlock_t
Parameters
s
Pointer to the
typedef seqcount_raw_spinlock_t
instancelock
Pointer to the associated raw_spinlock
-
typedef seqcount_rwlock_t
sequence count with rwlock associated
Description
A plain sequence counter with external writer synchronization by a rwlock. The rwlock is associated to the sequence count in the static initializer or init function. This enables lockdep to validate that the write side critical section is properly serialized.
-
SEQCNT_RWLOCK_ZERO ( name, lock)
static initializer for seqcount_rwlock_t
Parameters
name
Name of the
typedef seqcount_rwlock_t
instancelock
Pointer to the associated rwlock
-
seqcount_rwlock_init ( s, lock)
runtime initializer for seqcount_rwlock_t
Parameters
s
Pointer to the
typedef seqcount_rwlock_t
instancelock
Pointer to the associated rwlock
-
typedef seqcount_mutex_t
sequence count with mutex associated
Description
A plain sequence counter with external writer synchronization by a mutex. The mutex is associated to the sequence counter in the static initializer or init function. This enables lockdep to validate that the write side critical section is properly serialized.
The write side API functions write_seqcount_begin()/end() automatically disable and enable preemption when used with seqcount_mutex_t.
-
SEQCNT_MUTEX_ZERO ( name, lock)
static initializer for seqcount_mutex_t
Parameters
name
Name of the
typedef seqcount_mutex_t
instancelock
Pointer to the associated mutex
-
seqcount_mutex_init ( s, lock)
runtime initializer for seqcount_mutex_t
Parameters
s
Pointer to the
typedef seqcount_mutex_t
instancelock
Pointer to the associated mutex
-
typedef seqcount_ww_mutex_t
sequence count with ww_mutex associated
Description
A plain sequence counter with external writer synchronization by a ww_mutex. The ww_mutex is associated to the sequence counter in the static initializer or init function. This enables lockdep to validate that the write side critical section is properly serialized.
The write side API functions write_seqcount_begin()/end() automatically disable and enable preemption when used with seqcount_ww_mutex_t.
-
SEQCNT_WW_MUTEX_ZERO ( name, lock)
static initializer for seqcount_ww_mutex_t
Parameters
name
Name of the
typedef seqcount_ww_mutex_t
instancelock
Pointer to the associated ww_mutex
-
seqcount_ww_mutex_init ( s, lock)
runtime initializer for seqcount_ww_mutex_t
Parameters
s
Pointer to the
typedef seqcount_ww_mutex_t
instancelock
Pointer to the associated ww_mutex
-
seqlock_init ( sl)
dynamic initializer for seqlock_t
Parameters
sl
Pointer to the
typedef seqlock_t
instance
-
DEFINE_SEQLOCK ( sl)
Define a statically-allocated seqlock_t
Parameters
sl
Name of the
typedef seqlock_t
instance
-
unsigned
read_seqbegin
(const seqlock_t *sl)¶ start a seqlock_t read-side critical section
Parameters
const seqlock_t * sl
Pointer to
typedef seqlock_t
Description
read_seqbegin opens a read side critical section of the given
seqlock_t. Validity of the critical section is tested by checking
read_seqretry()
.
Return
count to be passed to read_seqretry()
-
unsigned
read_seqretry
(const seqlock_t *sl, unsigned start)¶ end and validate a seqlock_t read side section
Parameters
const seqlock_t * sl
Pointer to
typedef seqlock_t
unsigned start
count, from
read_seqbegin()
Description
read_seqretry closes the given seqlock_t read side critical section, and checks its validity. If the read section was invalid, it must be ignored and retried.
Return
1 if a retry is required, 0 otherwise
-
void
write_seqlock
(seqlock_t *sl)¶ start a seqlock_t write side critical section
Parameters
seqlock_t * sl
Pointer to
typedef seqlock_t
Description
write_seqlock opens a write side critical section of the given seqlock_t. It also acquires the spinlock_t embedded inside the sequential lock. All the seqlock_t write side critical sections are thus automatically serialized and non-preemptible.
Use the _irqsave
and _bh
variants instead if the read side
can be invoked from a hardirq or softirq context.
The opened write side section must be closed with write_sequnlock()
.
-
void
write_sequnlock
(seqlock_t *sl)¶ end a seqlock_t write side critical section
Parameters
seqlock_t * sl
Pointer to
typedef seqlock_t
Description
write_sequnlock closes the (serialized and non-preemptible) write side critical section of given seqlock_t.
-
void
write_seqlock_bh
(seqlock_t *sl)¶ start a softirqs-disabled seqlock_t write section
Parameters
seqlock_t * sl
Pointer to
typedef seqlock_t
Description
_bh
variant of write_seqlock()
. Use only if the read side section
can be invoked from a softirq context.
The opened write section must be closed with write_sequnlock_bh()
.
-
void
write_sequnlock_bh
(seqlock_t *sl)¶ end a softirqs-disabled seqlock_t write section
Parameters
seqlock_t * sl
Pointer to
typedef seqlock_t
Description
write_sequnlock_bh closes the serialized, non-preemptible,
softirqs-disabled, seqlock_t write side critical section opened with
write_seqlock_bh()
.
-
void
write_seqlock_irq
(seqlock_t *sl)¶ start a non-interruptible seqlock_t write side section
Parameters
seqlock_t * sl
Pointer to
typedef seqlock_t
Description
This is the _irq
variant of write_seqlock()
. Use only if the read
section of given seqlock_t can be invoked from a hardirq context.
-
void
write_sequnlock_irq
(seqlock_t *sl)¶ end a non-interruptible seqlock_t write side section
Parameters
seqlock_t * sl
Pointer to
typedef seqlock_t
Description
_irq
variant of write_sequnlock()
. The write side section of
given seqlock_t must’ve been opened with write_seqlock_irq()
.
-
write_seqlock_irqsave ( lock, flags)
start a non-interruptible seqlock_t write section
Parameters
lock
Pointer to
typedef seqlock_t
flags
Stack-allocated storage for saving caller’s local interrupt state, to be passed to
write_sequnlock_irqrestore()
.
Description
_irqsave
variant of write_seqlock()
. Use if the read section of
given seqlock_t can be invoked from a hardirq context.
The opened write section must be closed with write_sequnlock_irqrestore()
.
-
void
write_sequnlock_irqrestore
(seqlock_t *sl, unsigned long flags)¶ end non-interruptible seqlock_t write section
Parameters
seqlock_t * sl
Pointer to
typedef seqlock_t
unsigned long flags
Caller’s saved interrupt state, from write_seqlock_irqsave()
Description
_irqrestore
variant of write_sequnlock()
. The write section of
given seqlock_t must’ve been opened with write_seqlock_irqsave().
-
void
read_seqlock_excl
(seqlock_t *sl)¶ begin a seqlock_t locking reader critical section
Parameters
seqlock_t * sl
Pointer to
typedef seqlock_t
Description
read_seqlock_excl opens a locking reader critical section for the given seqlock_t. A locking reader exclusively locks out other writers and other locking readers, but doesn’t update the sequence number.
Locking readers act like a normal spin_lock()/spin_unlock().
The opened read side section must be closed with read_sequnlock_excl()
.
-
void
read_sequnlock_excl
(seqlock_t *sl)¶ end a seqlock_t locking reader critical section
Parameters
seqlock_t * sl
Pointer to
typedef seqlock_t
Description
read_sequnlock_excl closes the locking reader critical section opened
with read_seqlock_excl()
.
-
void
read_seqbegin_or_lock
(seqlock_t *lock, int *seq)¶ begin a seqlock_t lockless or locking reader
Parameters
seqlock_t * lock
Pointer to
typedef seqlock_t
int * seq
Marker and return parameter. If the passed value is even, the reader will become a lockless seqlock_t sequence counter reader as in
read_seqbegin()
. If the passed value is odd, the reader will become a fully locking reader, as inread_seqlock_excl()
. In the first call toread_seqbegin_or_lock()
, the caller must initialize and pass an even value to seq so a lockless read is optimistically tried first.
Description
read_seqbegin_or_lock is an API designed to optimistically try a
normal lockless seqlock_t read section first, as in read_seqbegin()
.
If an odd counter is found, the normal lockless read trial has
failed, and the next reader iteration transforms to a full seqlock_t
locking reader as in read_seqlock_excl()
.
This is typically used to avoid lockless seqlock_t readers starvation (too much retry loops) in the case of a sharp spike in write activity.
The opened read section must be closed with done_seqretry()
. Check
Documentation/locking/seqlock.rst for template example code.
Return
The encountered sequence counter value, returned through the
seq parameter, which is overloaded as a return parameter. The
returned value must be checked with need_seqretry()
. If the read
section must be retried, the returned value must also be passed to
the seq parameter of the next read_seqbegin_or_lock()
iteration.
-
int
need_seqretry
(seqlock_t *lock, int seq)¶ validate seqlock_t “locking or lockless” reader section
Parameters
seqlock_t * lock
Pointer to
typedef seqlock_t
int seq
count, from
read_seqbegin_or_lock()
Description
need_seqretry checks if the seqlock_t read-side critical section
started with read_seqbegin_or_lock()
is valid. If it was not, the
caller must retry the read-side section.
Return
1 if a retry is required, 0 otherwise
-
void
done_seqretry
(seqlock_t *lock, int seq)¶ end seqlock_t “locking or lockless” reader section
Parameters
seqlock_t * lock
Pointer to
typedef seqlock_t
int seq
count, from
read_seqbegin_or_lock()
Description
done_seqretry finishes the seqlock_t read side critical section
started by read_seqbegin_or_lock()
. The read section must’ve been
already validated with need_seqretry()
.
-
void
read_seqlock_excl_bh
(seqlock_t *sl)¶ start a locking reader seqlock_t section with softirqs disabled
Parameters
seqlock_t * sl
Pointer to
typedef seqlock_t
Description
_bh
variant of read_seqlock_excl()
. Use this variant if the
seqlock_t write side section, or other read sections, can be
invoked from a softirq context
The opened section must be closed with read_sequnlock_excl_bh()
.
-
void
read_sequnlock_excl_bh
(seqlock_t *sl)¶ stop a seqlock_t softirq-disabled locking reader section
Parameters
seqlock_t * sl
Pointer to
typedef seqlock_t
Description
_bh
variant of read_sequnlock_excl()
. The closed section must’ve
been opened with read_seqlock_excl_bh()
.
-
void
read_seqlock_excl_irq
(seqlock_t *sl)¶ start a non-interruptible seqlock_t locking reader section
Parameters
seqlock_t * sl
Pointer to
typedef seqlock_t
Description
_irq
variant of read_seqlock_excl()
. Use this only if the
seqlock_t write side critical section, or other read side sections,
can be invoked from a hardirq context.
The opened read section must be closed with read_sequnlock_excl_irq()
.
-
void
read_sequnlock_excl_irq
(seqlock_t *sl)¶ end an interrupts-disabled seqlock_t locking reader section
Parameters
seqlock_t * sl
Pointer to
typedef seqlock_t
Description
_irq
variant of read_sequnlock_excl()
. The closed section must’ve
been opened with read_seqlock_excl_irq()
.
-
read_seqlock_excl_irqsave ( lock, flags)
start a non-interruptible seqlock_t locking reader section
Parameters
lock
Pointer to
typedef seqlock_t
flags
Stack-allocated storage for saving caller’s local interrupt state, to be passed to
read_sequnlock_excl_irqrestore()
.
Description
_irqsave
variant of read_seqlock_excl()
. Use this only if the
seqlock_t write side critical section, or other read side sections,
can be invoked from a hardirq context.
Opened section must be closed with read_sequnlock_excl_irqrestore()
.
-
void
read_sequnlock_excl_irqrestore
(seqlock_t *sl, unsigned long flags)¶ end non-interruptible seqlock_t locking reader section
Parameters
seqlock_t * sl
Pointer to
typedef seqlock_t
unsigned long flags
Caller’s saved interrupt state, from read_seqlock_excl_irqsave()
Description
_irqrestore
variant of read_sequnlock_excl()
. The closed section
must’ve been opened with read_seqlock_excl_irqsave().
-
unsigned long
read_seqbegin_or_lock_irqsave
(seqlock_t *lock, int *seq)¶ begin a seqlock_t lockless reader, or a non-interruptible locking reader
Parameters
seqlock_t * lock
Pointer to
typedef seqlock_t
int * seq
Marker and return parameter. Check
read_seqbegin_or_lock()
.
Description
This is the _irqsave
variant of read_seqbegin_or_lock()
. Use if
the seqlock_t write side critical section, or other read side sections,
can be invoked from hardirq context.
The validity of the read section must be checked with need_seqretry()
.
The opened section must be closed with done_seqretry_irqrestore()
.
Return
The saved local interrupts state in case of a locking reader, to be passed to
done_seqretry_irqrestore()
.The encountered sequence counter value, returned through seq which is overloaded as a return parameter. Check
read_seqbegin_or_lock()
.
-
void
done_seqretry_irqrestore
(seqlock_t *lock, int seq, unsigned long flags)¶ end a seqlock_t lockless reader, or a non-interruptible locking reader section
Parameters
seqlock_t * lock
Pointer to
typedef seqlock_t
int seq
Count, from
read_seqbegin_or_lock_irqsave()
unsigned long flags
Caller’s saved local interrupt state in case of a locking reader, also from
read_seqbegin_or_lock_irqsave()
Description
This is the _irqrestore
variant of done_seqretry()
. The read
section must’ve been opened with read_seqbegin_or_lock_irqsave()
, and
validated with need_seqretry()
.