序列計數器和順序鎖¶
簡介¶
序列計數器是一種讀寫一致性機制,具有無鎖讀取器(只讀重試迴圈),並且沒有寫者飢餓。 它們用於很少寫入的資料(例如,系統時間),其中讀取器需要一組一致的資訊,並且願意在該資訊更改時重試。
當讀取端臨界區開始時的序列計數為偶數,並且在臨界區結束時再次讀取相同的序列計數值時,資料集是一致的。 集合中的資料必須在讀取端臨界區內複製出來。 如果在臨界區的開始和結束之間序列計數已更改,則讀取器必須重試。
寫者在其臨界區的開始和結束時遞增序列計數。 啟動臨界區後,序列計數為奇數,並向讀取器指示正在進行更新。 在寫入端臨界區的末尾,序列計數再次變為偶數,這使讀取器可以取得進展。
序列計數器寫入端臨界區絕不能被讀取端部分搶佔或中斷。 否則,由於奇數序列計數值和中斷的寫入器,讀取器將旋轉整個排程程式節拍。 如果該讀取器屬於即時排程類,則它可以永遠旋轉,並且核心將發生死鎖。
如果受保護的資料包含指標,則無法使用此機制,因為寫入器可能會使讀取器正在跟蹤的指標無效。
序列計數器 (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 的靜態初始化程式
引數
nameseqcount_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_try_begin¶
raw_seqcount_try_begin (s, start)
開始沒有 lockdep 且沒有計數器穩定的 seqcount_t 讀取臨界區
引數
s指向 seqcount_t 或任何 seqcount_LOCKNAME_t 變體的指標
start要傳遞給
read_seqcount_retry()的計數
描述
與 raw_seqcount_begin() 類似,除非它可以完全省略奇數的臨界區,而不是進行已知會失敗的推測。
當計數器穩定或多或少等同於獲取鎖並且存在執行此操作的慢速路徑時,此方法很有用。
如果為 true,則 start 將設定為讀取的(偶數)序列計數。
返回值
當啟動讀取臨界區時為 true。
-
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)
啟動沒有 lockdep 的 seqcount_t 寫入部分
-
raw_write_seqcount_end¶
raw_write_seqcount_end (s)
結束沒有 lockdep 的 seqcount_t 寫入部分
-
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-writer 臨界區中,該臨界區將確保讀取器知道正在進行的寫入
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_nameseqcount_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來自
raw_read_seqcount_latch()的計數
返回值
如果需要讀取部分重試,則為 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
引數
slseqlock_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 的指標
標誌用於儲存呼叫方的本地中斷狀態的堆疊分配儲存,要傳遞給
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 的指標
標誌用於儲存呼叫方的本地中斷狀態的堆疊分配儲存,要傳遞給
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標記和返回引數。 如果傳遞的值為偶數,則讀取器將成為一個_無鎖_ seqlock_t 讀取器,如
read_seqbegin()中所示。 如果傳遞的值為奇數,則讀取器將成為一個_鎖定_讀取器,如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計數,來自
read_seqbegin_or_lock()
描述
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 sequnsigned long flags呼叫者儲存的本地中斷狀態,在鎖定讀取器的情況下,也來自
read_seqbegin_or_lock_irqsave()
描述
這是 done_seqretry() 的 _irqrestore 變體。讀取段必須已使用 read_seqbegin_or_lock_irqsave() 開啟,並由 need_seqretry() 驗證。