序列计数器和顺序锁¶
简介¶
序列计数器是一种读写一致性机制,具有无锁读取器(只读重试循环),并且没有写入器饥饿。 它们用于很少写入的数据(例如系统时间),其中读取器需要一组一致的信息,并且如果该信息发生更改,则愿意重试。
当读取端临界区开始时的序列计数是偶数,并且在临界区末尾再次读取相同的序列计数值时,数据集是一致的。 必须在读取端临界区内复制出数据集中的数据。 如果序列计数在临界区的开始和结束之间发生更改,则读取器必须重试。
写入器在其临界区的开始和结束时递增序列计数。 启动临界区后,序列计数为奇数,并向读取器指示正在进行更新。 在写入端临界区结束时,序列计数再次变为偶数,这使读取器可以继续进行。
序列计数器写入端临界区绝不能被读取端部分抢占或中断。 否则,由于奇数序列计数值和被中断的写入器,读取器将在整个调度程序滴答内旋转。 如果该读取器属于实时调度类,则它可能会永远旋转,并且内核将发生活锁。
如果受保护的数据包含指针,则不能使用此机制,因为写入器可能会使读取器正在跟踪的指针无效。
序列计数器 (seqcount_t
)¶
这是原始计数机制,它不能防止多个写入器。 因此,必须通过外部锁来序列化写入端临界区。
如果写入序列化原语没有隐式禁用抢占,则必须在进入写入端部分之前显式禁用抢占。 如果可以从硬中断或软中断上下文中调用读取部分,则还必须在进入写入部分之前分别禁用中断或下半部分。
如果希望自动处理写入器序列化和不可抢占的序列计数器要求,请改用 顺序锁 (seqlock_t)。
初始化
/* 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;
写入路径
/* Serialized context with disabled preemption */
write_seqcount_begin(&foo_seqcount);
/* ... [[write-side critical section]] ... */
write_seqcount_end(&foo_seqcount);
读取路径
do {
seq = read_seqcount_begin(&foo_seqcount);
/* ... [[read-side critical section]] ... */
} while (read_seqcount_retry(&foo_seqcount, seq));
具有关联锁的序列计数器 (seqcount_LOCKNAME_t
)¶
如 序列计数器 (seqcount_t) 中所述,必须序列化序列计数写入端临界区且不可抢占。 此序列计数器的变体在初始化时关联用于写入器序列化的锁,这使 lockdep 能够验证是否正确序列化了写入端临界区。
如果禁用 lockdep,则此锁关联是 NOOP,并且既没有存储开销也没有运行时开销。 如果启用 lockdep,则锁指针存储在 struct seqcount 中,并且在写入端临界区的开头注入 lockdep 的“持有锁”断言,以验证它是否受到正确保护。
对于不隐式禁用抢占的锁类型,在写入端函数中强制执行抢占保护。
定义了以下具有关联锁的序列计数器
seqcount_spinlock_t
seqcount_raw_spinlock_t
seqcount_rwlock_t
seqcount_mutex_t
seqcount_ww_mutex_t
序列计数器读取和写入 API 可以采用普通的 seqcount_t 或任何上述 seqcount_LOCKNAME_t 变体。
初始化(将“LOCKNAME”替换为受支持的锁之一)
/* dynamic */
seqcount_LOCKNAME_t foo_seqcount;
seqcount_LOCKNAME_init(&foo_seqcount, &lock);
/* static */
static seqcount_LOCKNAME_t foo_seqcount =
SEQCNT_LOCKNAME_ZERO(foo_seqcount, &lock);
/* C99 struct init */
struct {
.seq = SEQCNT_LOCKNAME_ZERO(foo.seq, &lock),
} foo;
写入路径:与 序列计数器 (seqcount_t) 中的相同,同时从获取了关联写入序列化锁的上下文中运行。
读取路径:与 序列计数器 (seqcount_t) 中的相同。
闩锁序列计数器 (seqcount_latch_t
)¶
闩锁序列计数器是一种多版本并发控制机制,其中嵌入式 seqcount_t 计数器的偶数/奇数值用于在受保护数据的两个副本之间切换。 这允许序列计数器读取路径安全地中断其自身的写入端临界区。
当写入端部分无法防止读取器中断时,请使用 seqcount_latch_t。 当可以从 NMI 处理程序调用读取端时,通常是这种情况。
有关更多信息,请查看 write_seqcount_latch()
。
顺序锁 (seqlock_t
)¶
这包含前面讨论的 序列计数器 (seqcount_t) 机制,以及用于写入器序列化和不可抢占的嵌入式自旋锁。
如果可以从硬中断或软中断上下文中调用读取端部分,请使用分别禁用中断或下半部分的写入端函数变体。
初始化
/* 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_seqlock(&foo_seqlock);
/* ... [[write-side critical section]] ... */
write_sequnlock(&foo_seqlock);
读取路径,分为三类
正常序列读取器,它们永远不会阻塞写入器,但如果写入器正在进行中,则必须通过检测序列号中的更改来重试。 写入器不等待序列读取器
do { seq = read_seqbegin(&foo_seqlock); /* ... [[read-side critical section]] ... */ } while (read_seqretry(&foo_seqlock, seq));
锁定读取器,如果写入器或另一个锁定读取器正在进行中,则将等待。 正在进行的锁定读取器还将阻止写入器进入其临界区。 此读取锁是互斥的。 与 rwlock_t 不同,只能有一个锁定读取器可以获取它
read_seqlock_excl(&foo_seqlock); /* ... [[read-side critical section]] ... */ read_sequnlock_excl(&foo_seqlock);
根据传递的标记,条件无锁读取器(如 1 中)或锁定读取器(如 2 中)。 这用于在写入活动急剧增加的情况下避免无锁读取器饥饿(重试循环过多)。 首先,尝试无锁读取(传递偶数标记)。 如果该尝试失败(返回奇数序列计数器,该计数器用作下一个迭代标记),则将无锁读取转换为完全锁定读取,并且不需要重试循环
/* 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 文档¶
-
seqcount_init¶
seqcount_init (s)
seqcount_t 的运行时初始化程序
参数
s
指向 seqcount_t 实例的指针
-
SEQCNT_ZERO¶
SEQCNT_ZERO (name)
seqcount_t 的静态初始化程序
参数
name
seqcount_t 实例的名称
-
__read_seqcount_begin¶
__read_seqcount_begin (s)
开始 seqcount_t 读取部分
-
raw_read_seqcount_begin¶
raw_read_seqcount_begin (s)
开始不带 lockdep 的 seqcount_t 读取部分
-
read_seqcount_begin¶
read_seqcount_begin (s)
开始 seqcount_t 读取临界区
-
raw_read_seqcount¶
raw_read_seqcount (s)
读取原始 seqcount_t 计数值
参数
s
指向 seqcount_t 或任何 seqcount_LOCKNAME_t 变体的指针
描述
raw_read_seqcount 打开给定 seqcount_t 的读取临界区,而无需任何 lockdep 检查,也无需检查或屏蔽序列计数器 LSB。 调用代码负责处理该问题。
返回
要传递给 read_seqcount_retry()
的计数
-
raw_seqcount_begin¶
raw_seqcount_begin (s)
开始不带 lockdep 且不带计数器稳定的 seqcount_t 读取临界区
参数
s
指向 seqcount_t 或任何 seqcount_LOCKNAME_t 变体的指针
描述
raw_seqcount_begin 打开给定 seqcount_t 的读取临界区。 与 read_seqcount_begin()
不同,此函数不会等待计数稳定。 如果在它开始时写入器处于活动状态,则它将使读取临界区末尾的 read_seqcount_retry()
失败,而不是在其开头稳定下来。
仅在读取部分较小且通过其他外部方式很可能成功的情况下,才在特殊的内核热路径中使用此方法。 它将节省单个分支指令。
返回
要传递给 read_seqcount_retry()
的计数
-
__read_seqcount_retry¶
__read_seqcount_retry (s, start)
结束一个 seqcount_t 读取段,不带屏障
参数
s
指向 seqcount_t 或任何 seqcount_LOCKNAME_t 变体的指针
start
计数,来自
read_seqcount_begin()
描述
__read_seqcount_retry 类似于 read_seqcount_retry,但不包含 smp_rmb() 屏障。调用者应确保在实际加载此临界区中要保护的任何变量之前,提供 smp_rmb() 或等效的排序。
请谨慎使用,仅在关键代码中使用,并注释如何提供屏障。
返回
如果需要重试读取段,则为 true,否则为 false
-
read_seqcount_retry¶
read_seqcount_retry (s, start)
结束一个 seqcount_t 读取临界区
参数
s
指向 seqcount_t 或任何 seqcount_LOCKNAME_t 变体的指针
start
计数,来自
read_seqcount_begin()
描述
read_seqcount_retry 关闭给定 seqcount_t 的读取临界区。如果临界区无效,则必须忽略(并通常重试)。
返回
如果需要重试读取段,则为 true,否则为 false
-
raw_write_seqcount_begin¶
raw_write_seqcount_begin (s)
开始一个 seqcount_t 写入段,不带 lockdep
-
raw_write_seqcount_end¶
raw_write_seqcount_end (s)
结束一个 seqcount_t 写入段,不带 lockdep
-
write_seqcount_begin_nested¶
write_seqcount_begin_nested (s, subclass)
开始一个具有自定义 lockdep 嵌套级别的 seqcount_t 写入段
-
write_seqcount_begin¶
write_seqcount_begin (s)
开始一个 seqcount_t 写入端临界区
参数
s
指向 seqcount_t 或任何 seqcount_LOCKNAME_t 变体的指针
上下文
序列计数器写入端段必须是串行化的且不可抢占的。当且仅当 seqcount 写入串行化锁已关联且可抢占时,才会自动禁用抢占。如果可以从硬中断或软中断上下文调用读取器,则必须分别禁用中断或下半部分。
-
write_seqcount_end¶
write_seqcount_end (s)
结束一个 seqcount_t 写入端临界区
参数
s
指向 seqcount_t 或任何 seqcount_LOCKNAME_t 变体的指针
上下文
当且仅当 seqcount 写入串行化锁已关联且可抢占时,才会自动重新启用抢占。
-
raw_write_seqcount_barrier¶
raw_write_seqcount_barrier (s)
执行一个 seqcount_t 写入屏障
参数
s
指向 seqcount_t 或任何 seqcount_LOCKNAME_t 变体的指针
描述
这可以用来提供排序保证,而不是通常的一致性保证。它便宜一个 wmb,因为它能折叠两个背靠背的 wmb()。
请注意,屏障周围的写入操作应声明为原子的(例如,通过 WRITE_ONCE):a) 确保写入操作对其他线程以原子方式可见,避免编译器优化; b) 记录哪些写入操作是要传播到读取器临界区的。这是必要的,因为屏障之前或之后的写入操作都不在 seq-写入器临界区中,后者将确保读取器意识到正在进行的写入操作
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)
{
WRITE_ONCE(Y, true);
raw_write_seqcount_barrier(seq);
WRITE_ONCE(X, false);
}
-
write_seqcount_invalidate¶
write_seqcount_invalidate (s)
使正在进行的 seqcount_t 读取端操作无效
参数
s
指向 seqcount_t 或任何 seqcount_LOCKNAME_t 变体的指针
描述
在 write_seqcount_invalidate 之后,将没有 seqcount_t 读取端操作会成功完成并看到早于此时间的数据。
-
SEQCNT_LATCH_ZERO¶
SEQCNT_LATCH_ZERO (seq_name)
seqcount_latch_t 的静态初始化器
参数
seq_name
seqcount_latch_t 实例的名称
-
seqcount_latch_init¶
seqcount_latch_init (s)
seqcount_latch_t 的运行时初始化器
参数
s
指向 seqcount_latch_t 实例的指针
-
unsigned raw_read_seqcount_latch(const seqcount_latch_t *s)¶
选取偶数/奇数锁存器数据副本
参数
const seqcount_latch_t *s
指向 seqcount_latch_t 的指针
描述
有关详细信息和完整的读取器/写入器用法示例,请参阅 raw_write_seqcount_latch()
。
返回
序列计数器原始值。使用最低位作为索引,选择要读取的数据副本。然后必须使用 raw_read_seqcount_latch_retry()
检查完整计数器。
-
unsigned read_seqcount_latch(const seqcount_latch_t *s)¶
选取偶数/奇数锁存器数据副本
参数
const seqcount_latch_t *s
指向 seqcount_latch_t 的指针
描述
有关详细信息和完整的读取器/写入器用法示例,请参阅 write_seqcount_latch()
。
返回
序列计数器原始值。使用最低位作为索引,选择要读取的数据副本。然后必须使用 read_seqcount_latch_retry()
检查完整计数器。
-
int raw_read_seqcount_latch_retry(const seqcount_latch_t *s, unsigned start)¶
结束一个 seqcount_latch_t 读取段
参数
const seqcount_latch_t *s
指向 seqcount_latch_t 的指针
unsigned start
返回
如果需要重试读取段,则为 true,否则为 false
-
int read_seqcount_latch_retry(const seqcount_latch_t *s, unsigned start)¶
结束一个 seqcount_latch_t 读取段
参数
const seqcount_latch_t *s
指向 seqcount_latch_t 的指针
unsigned start
计数,来自
read_seqcount_latch()
返回
如果需要重试读取段,则为 true,否则为 false
-
void raw_write_seqcount_latch(seqcount_latch_t *s)¶
将锁存器读取器重定向到偶数/奇数副本
参数
seqcount_latch_t *s
指向 seqcount_latch_t 的指针
-
void write_seqcount_latch_begin(seqcount_latch_t *s)¶
将锁存器读取器重定向到奇数副本
参数
seqcount_latch_t *s
指向 seqcount_latch_t 的指针
描述
锁存器技术是一种多版本并发控制方法,允许在非原子修改期间进行查询。如果您可以保证查询永远不会中断修改(例如,并发严格在 CPU 之间),则很可能不需要此方法。
传统的 RCU/无锁数据结构依赖于原子修改来确保查询观察到旧状态或新状态,而锁存器允许对非原子更新执行相同的操作。权衡是存储成本加倍;我们必须维护整个数据结构的两个副本。
简单来说:我们首先修改一个副本,然后再修改另一个副本。这确保始终有一个副本处于稳定状态,可以给我们答案。
基本形式是类似于这样的数据结构
struct latch_struct {
seqcount_latch_t seq;
struct data_struct data[2];
};
其中假定在外部串行化的修改执行以下操作
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);
}
查询将具有如下形式
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;
}
因此,在修改期间,查询首先被重定向到 data[1]。然后我们修改 data[0]。完成后,我们将查询重定向回 data[0],然后我们可以修改 data[1]。
注意2
当数据是动态数据结构时,应使用常规 RCU 模式来管理其中对象的生命周期。
注意
对于数据是动态数据结构的情况,对原子修改的非要求_不_包括发布新条目。
迭代可能从 data[0] 开始,并被挂起足够长的时间以错过整个修改序列,一旦恢复,它可能会观察到新条目。
-
void write_seqcount_latch(seqcount_latch_t *s)¶
将锁存读取器重定向到偶数副本
参数
seqcount_latch_t *s
指向 seqcount_latch_t 的指针
-
void write_seqcount_latch_end(seqcount_latch_t *s)¶
结束 seqcount_latch_t 写入段
参数
seqcount_latch_t *s
指向 seqcount_latch_t 的指针
描述
标记 seqcount_latch_t 写入器段的结束,此时锁存保护数据的所有副本都已更新。
-
seqlock_init¶
seqlock_init (sl)
seqlock_t 的动态初始化器
参数
sl
指向 seqlock_t 实例的指针
-
DEFINE_SEQLOCK¶
DEFINE_SEQLOCK (sl)
定义一个静态分配的 seqlock_t
参数
sl
seqlock_t 实例的名称
-
unsigned read_seqbegin(const seqlock_t *sl)¶
启动 seqlock_t 读取侧临界区
-
unsigned read_seqretry(const seqlock_t *sl, unsigned start)¶
结束 seqlock_t 读取侧段
参数
const seqlock_t *sl
指向 seqlock_t 的指针
unsigned start
来自
read_seqbegin()
的计数
描述
read_seqretry 关闭给定 seqlock_t 的读取侧临界区。如果临界区无效,则必须忽略(并且通常会重试)。
返回
如果需要重试读取段,则为 true,否则为 false
-
void write_seqlock(seqlock_t *sl)¶
启动 seqlock_t 写入侧临界区
参数
seqlock_t *sl
指向 seqlock_t 的指针
描述
write_seqlock 为给定的 seqlock_t 打开写入侧临界区。它还隐式获取嵌入在该顺序锁内的 spinlock_t。因此,所有 seqlock_t 写入侧段都会自动序列化且不可抢占。
上下文
如果可以从硬中断或软中断上下文中调用 seqlock_t 读取段或其他写入侧临界区,请改用此函数的 _irqsave 或 _bh 变体。
-
void write_sequnlock(seqlock_t *sl)¶
结束 seqlock_t 写入侧临界区
参数
seqlock_t *sl
指向 seqlock_t 的指针
描述
write_sequnlock 关闭给定 seqlock_t 的(序列化且不可抢占的)写入侧临界区。
-
void write_seqlock_bh(seqlock_t *sl)¶
启动禁用软中断的 seqlock_t 写入段
-
void write_sequnlock_bh(seqlock_t *sl)¶
结束禁用软中断的 seqlock_t 写入段
参数
seqlock_t *sl
指向 seqlock_t 的指针
描述
write_sequnlock_bh 关闭通过 write_seqlock_bh()
打开的序列化、不可抢占和禁用软中断的 seqlock_t 写入侧临界区。
-
void write_seqlock_irq(seqlock_t *sl)¶
启动不可中断的 seqlock_t 写入段
-
void write_sequnlock_irq(seqlock_t *sl)¶
结束不可中断的 seqlock_t 写入段
参数
seqlock_t *sl
指向 seqlock_t 的指针
描述
write_sequnlock_irq 关闭通过 write_seqlock_irq()
打开的序列化且不可中断的 seqlock_t 写入侧段。
-
write_seqlock_irqsave¶
write_seqlock_irqsave (lock, flags)
启动不可中断的 seqlock_t 写入段
参数
lock
指向 seqlock_t 的指针
flags
用于保存调用方本地中断状态的堆栈分配存储,将传递给
write_sequnlock_irqrestore()
。
描述
write_seqlock()
的 _irqsave 变体。仅当可以从硬中断上下文中调用读取侧段或其他写入段时才使用。
-
void write_sequnlock_irqrestore(seqlock_t *sl, unsigned long flags)¶
结束不可中断的 seqlock_t 写入段
参数
seqlock_t *sl
指向 seqlock_t 的指针
unsigned long flags
调用方保存的中断状态,来自
write_seqlock_irqsave()
描述
write_sequnlock_irqrestore 关闭先前通过 write_seqlock_irqsave()
打开的序列化且不可中断的 seqlock_t 写入段。
-
void read_seqlock_excl(seqlock_t *sl)¶
开始 seqlock_t 锁定读取器段
参数
seqlock_t *sl
指向 seqlock_t 的指针
描述
read_seqlock_excl 打开 seqlock_t 锁定读取器临界区。锁定读取器会独占锁定其他写入器和其他锁定读取器,但它不会更新嵌入的序列号。
锁定读取器的行为类似于普通的 spin_lock()/spin_unlock()。
打开的读取段必须使用 read_sequnlock_excl()
关闭。
上下文
如果可以从硬中断或软中断上下文中调用 seqlock_t 写入段或其他读取段,请改用此函数的 _irqsave 或 _bh 变体。
-
void read_sequnlock_excl(seqlock_t *sl)¶
结束 seqlock_t 锁定读取器临界区
参数
seqlock_t *sl
指向 seqlock_t 的指针
-
void read_seqlock_excl_bh(seqlock_t *sl)¶
启动禁用软中断的 seqlock_t 锁定读取器段
参数
seqlock_t *sl
指向 seqlock_t 的指针
描述
read_seqlock_excl()
的 _bh 变体。仅当可以从软中断上下文中调用 seqlock_t 写入侧段或其他读取段时才使用此变体。
-
void read_sequnlock_excl_bh(seqlock_t *sl)¶
停止 seqlock_t 禁用软中断的锁定读取器段
参数
seqlock_t *sl
指向 seqlock_t 的指针
-
void read_seqlock_excl_irq(seqlock_t *sl)¶
启动一个不可中断的 seqlock_t 锁定读取器部分
参数
seqlock_t *sl
指向 seqlock_t 的指针
描述
read_seqlock_excl()
的 _irq 变体。 仅当 seqlock_t 写入侧部分,*或其他读取部分* 可以从硬中断上下文调用时才使用此函数。
-
void read_sequnlock_excl_irq(seqlock_t *sl)¶
结束一个禁用中断的 seqlock_t 锁定读取器部分
参数
seqlock_t *sl
指向 seqlock_t 的指针
-
read_seqlock_excl_irqsave¶
read_seqlock_excl_irqsave (lock, flags)
启动一个不可中断的 seqlock_t 锁定读取器部分
参数
lock
指向 seqlock_t 的指针
flags
用于保存调用者的本地中断状态的堆栈分配存储空间,将传递给
read_sequnlock_excl_irqrestore()
。
描述
read_seqlock_excl()
的 _irqsave 变体。 仅当 seqlock_t 写入侧部分,*或其他读取部分* 可以从硬中断上下文调用时才使用此函数。
-
void read_sequnlock_excl_irqrestore(seqlock_t *sl, unsigned long flags)¶
结束不可中断的 seqlock_t 锁定读取器部分
参数
seqlock_t *sl
指向 seqlock_t 的指针
unsigned long flags
调用者保存的中断状态,来自
read_seqlock_excl_irqsave()
-
void read_seqbegin_or_lock(seqlock_t *lock, int *seq)¶
开始一个 seqlock_t 无锁或锁定读取器
参数
seqlock_t *lock
指向 seqlock_t 的指针
int *seq
标记和返回参数。如果传递的值为偶数,则读取器将像
read_seqbegin()
一样成为*无锁* seqlock_t 读取器。如果传递的值为奇数,则读取器将像read_seqlock_excl()
一样成为*锁定* 读取器。在第一次调用此函数时,调用者*必须*初始化并将偶数值传递给**seq**;这样,可以首先乐观地尝试无锁读取。
描述
read_seqbegin_or_lock 是一个 API,旨在首先乐观地尝试正常的无锁 seqlock_t 读取部分。如果找到奇数计数器,则无锁读取尝试失败,并且下一个读取迭代将其自身转换为完全的 seqlock_t 锁定读取器。
这通常用于避免在写入侧活动急剧增加的情况下 seqlock_t 无锁读取器饥饿(重试循环过多)。
请查看序列计数器和顺序锁以获取模板示例代码。
上下文
如果可以从硬中断或软中断上下文中调用 seqlock_t 写入段或其他读取段,请改用此函数的 _irqsave 或 _bh 变体。
返回
通过 **seq** 参数(重载为返回参数)遇到的序列计数器值。此返回值必须使用need_seqretry()
进行检查。如果需要重试读取部分,则此返回值还必须作为下一次read_seqbegin_or_lock()
迭代的 **seq** 参数传递。
-
int need_seqretry(seqlock_t *lock, int seq)¶
验证 seqlock_t “锁定或无锁” 读取部分
参数
seqlock_t *lock
指向 seqlock_t 的指针
int seq
序列计数,来自
read_seqbegin_or_lock()
返回
如果需要重试读取部分,则为 true;否则为 false
-
void done_seqretry(seqlock_t *lock, int seq)¶
结束 seqlock_t “锁定或无锁” 读取器部分
参数
seqlock_t *lock
指向 seqlock_t 的指针
int seq
描述
done_seqretry 完成由read_seqbegin_or_lock()
启动并由need_seqretry()
验证的 seqlock_t 读取侧关键部分。
-
unsigned long read_seqbegin_or_lock_irqsave(seqlock_t *lock, int *seq)¶
开始一个 seqlock_t 无锁读取器或一个不可中断的锁定读取器
参数
seqlock_t *lock
指向 seqlock_t 的指针
int *seq
标记和返回参数。请查看
read_seqbegin_or_lock()
。
描述
这是read_seqbegin_or_lock()
的 _irqsave 变体。仅当 seqlock_t 写入部分*或其他读取部分*可以从硬中断上下文调用时才使用它。
注意
仅在“锁定读取器”模式下禁用中断。
返回
锁定读取器情况下保存的本地中断状态,将传递给
done_seqretry_irqrestore()
。遇到的序列计数器值,通过重载为返回参数的 **seq** 返回。请查看
read_seqbegin_or_lock()
。
-
void done_seqretry_irqrestore(seqlock_t *lock, int seq, unsigned long flags)¶
结束 seqlock_t 无锁读取器或不可中断的锁定读取器部分
参数
seqlock_t *lock
指向 seqlock_t 的指针
int seq
unsigned long flags
调用者保存的本地中断状态,在锁定读取器的情况下也来自
read_seqbegin_or_lock_irqsave()
描述
这是done_seqretry()
的 _irqrestore 变体。读取部分必须使用read_seqbegin_or_lock_irqsave()
打开,并由need_seqretry()
验证。