国产6699视频在线观看_女人爽到喷水的视频大全_亚洲欧美日韩国产视频亚洲欧美综合日韩久久_中文字幕无码久久东京热_av电影中文一区

 
首頁 > 白銀 >
 
 

世界頭條:Linux內(nèi)核同步機制原子操作詳解

2023-06-27 02:20:07  來源:嵌入式Linux開發(fā)

Linux內(nèi)核同步機制原子操作

變量的修改

我們平時的編程中可能經(jīng)常需要修改變量和寄存器,大概是這樣操作的:

讀一個位于memory中的變量的值然后寫到寄存器中修改該變量的值將寄存器中的值寫回memory中的變量值 如果這三個步驟是串行化的,并且是在一個線程中串行執(zhí)行,那么這樣做是沒有問題的,然而,世界中的事情總是不能如你所愿。在多CPU體系架構(gòu)中,運行在兩個CPU上的兩個內(nèi)核控制路徑同時并行執(zhí)行上面操作序列,有可能發(fā)生下面的場景:

CPU和內(nèi)存是通過總線進行互聯(lián)的,在任意時刻,只能有一個CPU訪問內(nèi)存。因此,來自兩個CPU上的讀內(nèi)存操作被串行化執(zhí)行,分別獲得了同樣的舊值。完成修改后,兩個CPU都想進行寫操作,把修改之后的值寫回到內(nèi)存。但是,CPU的寫回操作也必須是串行化的,因此CPU1首先獲得了訪問權(quán),進行寫回動作,隨后,CPU2完成寫回動作。在這種情況下,CPU1的對內(nèi)存的修改被CPU2的寫操作覆蓋了,因此執(zhí)行結(jié)果是錯誤的。

不僅是多CPU會存在這種問題,在單CPU上也會由于內(nèi)核控制路徑的交錯導致上面的錯誤。一個簡單的例子就是中斷:


(相關(guān)資料圖)

系統(tǒng)調(diào)用的控制路徑上,完成讀操作之后,硬件觸發(fā)中斷,開始執(zhí)行中斷處理函數(shù)。中斷處理函數(shù)的寫回操作被系統(tǒng)調(diào)用控制路徑上的寫回操作覆蓋了,導致結(jié)果不一致。

正確的操作

對于那些有多個內(nèi)核控制路徑進行讀-修改-寫回的變量,內(nèi)核提供了一個特殊的類型atomic_t,具體定義如下:

typedef struct { int counter;} atomic_t;

從定義上來看,atomic_t實際上就是一個int類型的變量counter,內(nèi)核中定義了很多關(guān)于atomic_xxx的接口函數(shù),這些函數(shù)只會接收atomic_t類型的參數(shù)。這樣就確保了atomic_xxx的函數(shù)只會操作atomic_t類型的數(shù)據(jù)。

內(nèi)核中具體的接口API函數(shù)如下:

接口函數(shù)功能描述
staticinline void atomic_add(int i, atomic_t *v)原子變量v增加i
static inline void atomic_sub(int i, atomic_t *v)原子變量v減去i
static inline void atomic_inc(atomic_t *v)原子變量增加1
static inline void atomic_dec(atomic_t *v)原子變量減去1
static inline int atomic_read(const atomic_t *v)讀取原子變量的值
static inline void atomic_set(atomic_t *v, int i)設(shè)置原子變量的值
static inline int atomic_dec_and_test(atomic_t *v)原子變量的值減去1,判斷原子變量的值是否等于0
static inline int atomic_cmpxchg(atomic_t *v, int oldval, int newval)比較oldval的值和原子變量v的值是否相等,如果相等,把newval的值賦值給原子變量v

底層實現(xiàn)原理

ARMv6之前的CPU并不支持SMP架構(gòu),之后的ARM架構(gòu)都是支持SMP架構(gòu)的。內(nèi)核中關(guān)于原子操作的實現(xiàn)通過#if __LINUX_ARM_ARCH__ >= 6條件變量進行區(qū)分。ARMv6之前的實現(xiàn)原理是通過關(guān)閉CPU中斷實現(xiàn)的,ARMv6之后的實現(xiàn)是通過新增加的兩個CPU指令ldrex、strex實現(xiàn)的。 通過下面的代碼可以具體的看到實現(xiàn)的細節(jié):

prefetchhw是預取操作和cache有關(guān),主要是為了提高性能。__volatile__主要是用來防止編譯器優(yōu)化的。在編譯c代碼的時候,如果使用優(yōu)化選項(-O)進行編譯,對于那些沒有聲明__volatile__嵌入式匯編代碼,編譯器有可能會對其進行編譯優(yōu)化,編譯的結(jié)果可能不是原來的匯編代碼,有了__volatile__之后,編譯器就會停止對該段代碼的任何優(yōu)化。

獨占訪問指令ldrex和strex

ldrex/strex是ARMv6架構(gòu)及之后架構(gòu)的同步原語,屬于硬件層面的同步機制。只要某個時刻只允許一個執(zhí)行單元訪問共享資源那么就必須進行同步,共享資源可以是內(nèi)存、外設(shè)設(shè)備,執(zhí)行單元可以是處理器、進程或者線程。

ldrex/strex這兩個指令配合獨占監(jiān)控器(獨占監(jiān)控器會跟蹤獨占內(nèi)存訪問)可以實現(xiàn)原子地更新內(nèi)存數(shù)據(jù)。

ldrex R1, [R0]ldrex指令從R0寄存器表示的地址中讀取一個字,存放在R1寄存器中,并且更新獨占監(jiān)控器狀態(tài)為獨占狀態(tài)
strex < Rd >, < Rt >, [< Rn >]strex指令存儲一個字到內(nèi)存中,但是這個存儲指令是有條件的,如果獨占監(jiān)控器允許這個存儲操作,那么對應(yīng)的內(nèi)存地址就會更新,并且將返回值0保存在目標寄存器中,代表此次操作成功。如果獨占監(jiān)控器不允許存儲操作,那么就不會更新獨占監(jiān)控器,并且將返回值1保存在目標寄存器中,代表此次操作失敗。

獨占監(jiān)控器

在上面的描述中我們提到獨占監(jiān)控器,獨占監(jiān)控器是一種簡單的狀態(tài)機,有兩種狀態(tài):打開或者獨占。為了實現(xiàn)多個處理器間的同步,一般會存在兩類獨占監(jiān)控器:本地監(jiān)控器和全局監(jiān)控器。

"1: ldrex %0, [%3]\\n"其中%3就是input operand list中的"r" (&v->counter),r是限制符(constraint),用來告訴編譯器gcc,選擇一個通用寄存器保存該操作數(shù)。%0對應(yīng)output openrand list中的"=&r" (result),=表示該操作數(shù)是write only的,&表示該操作數(shù)是一個earlyclobber operand,編譯器在處理嵌入式匯編的時候,傾向于使用盡可能少的寄存器,如果output operand沒有&修飾的話,匯編指令中的inputoutput操作數(shù)會使用同一個寄存器。&確保了%3%0使用不同的寄存器?,F(xiàn)在%0這個output操作數(shù)已經(jīng)被賦值為atomic_t變量的old value,毫無疑問,這里的操作是要給old value加上i。這里%4對應(yīng)"Ir" (i),這里“I”表示這是一個有特定限制的立即數(shù),該數(shù)必須是0~255之間的一個整數(shù)通過rotation的操作得到的一個32bit的立即數(shù)。每個指令32個bit,其中12個bit被用來表示立即數(shù),其中8個bit是真正的數(shù)據(jù),4個bit用來表示如何rotation。這一步將修改后的new value保存在atomic_t變量中。是否能夠正確操作的狀態(tài)標記保存在%1操作數(shù)中,也就是"=&r" (tmp)。最后檢查memory update的操作是否正確完成,如果發(fā)生了問題,需要跳轉(zhuǎn)到lable 1那里,重新進行一次read-modify-write的操作。

#define ATOMIC_OP(op, c_op, asm_op)     \\static inline void atomic_##op(int i, atomic_t *v)   \\{         \\ unsigned long tmp;      \\ int result;       \\         \\ prefetchw(&v- >counter);      \\ __asm__ __volatile__("@ atomic_" #op "\\n"   \\"1: ldrex %0, [%3]\\n"      \\" " #asm_op " %0, %0, %4\\n"     \\" strex %1, %0, [%3]\\n"      \\" teq %1, #0\\n"      \\" bne 1b"       \\ : "=&r" (result), "=&r" (tmp), "+Qo" (v- >counter)  \\ : "r" (&v- >counter), "Ir" (i)     \\ : "cc");       \\}
#define ATOMIC_OP(op, c_op, asm_op)     \\static inline void atomic_##op(int i, atomic_t *v)   \\{         \\ unsigned long flags;      \\         \\ raw_local_irq_save(flags);     \\ v- >counter c_op i;      \\ raw_local_irq_restore(flags);     \\}

總結(jié)

本篇主要介紹了Linux內(nèi)核的同步機制之一原子操作,從原子的操作的API接口到原子操作的底層實現(xiàn)原理,進行了簡單分析。

關(guān)鍵詞:

  
相關(guān)新聞
每日推薦
  • 滾動
  • 綜合
  • 房產(chǎn)