色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Linux內核同步機制之原子操作

Linux閱碼場 ? 來源:lq ? 2018-12-13 14:05 ? 次閱讀

一、源由

我們的程序邏輯經常遇到這樣的操作序列:

1、讀一個位于memory中的變量的值到寄存器

2、修改該變量的值(也就是修改寄存器中的值)

3、將寄存器中的數值寫回memory中的變量值

如果這個操作序列是串行化的操作(在一個thread中串行執行),那么一切OK,然而,世界總是不能如你所愿。在多CPU體系結構中,運行在兩個CPU上的兩個內核控制路徑同時并行執行上面操作序列,有可能發生下面的場景:

多個CPUs和memory chip是通過總線互聯的,在任意時刻,只能有一個總線master設備(例如CPU、DMA controller)訪問該Slave設備(在這個場景中,slave設備是RAM chip)。因此,來自兩個CPU上的讀memory操作被串行化執行,分別獲得了同樣的舊值。完成修改后,兩個CPU都想進行寫操作,把修改的值寫回到memory。但是,硬件arbiter的限制使得CPU的寫回必須是串行化的,因此CPU1首先獲得了訪問權,進行寫回動作,隨后,CPU2完成寫回動作。在這種情況下,CPU1的對memory的修改被CPU2的操作覆蓋了,因此執行結果是錯誤的。

不僅是多CPU,在單CPU上也會由于有多個內核控制路徑的交錯而導致上面描述的錯誤。一個具體的例子如下:

系統調用的控制路徑上,完成讀操作后,硬件觸發中斷,開始執行中斷handler。這種場景下,中斷handler控制路徑的寫回的操作被系統調用控制路徑上的寫回覆蓋了,結果也是錯誤的。

二、對策

對于那些有多個內核控制路徑進行read-modify-write的變量,內核提供了一個特殊的類型atomic_t,具體定義如下:

從上面的定義來看,atomic_t實際上就是一個int類型的counter,不過定義這樣特殊的類型atomic_t是有其思考的:內核定義了若干atomic_xxx的接口API函數,這些函數只會接收atomic_t類型的參數。這樣可以確保atomic_xxx的接口函數只會操作atomic_t類型的數據。同樣的,如果你定義了atomic_t類型的變量(你期望用atomic_xxx的接口API函數操作它),這些變量也不會被那些普通的、非原子變量操作的API函數接受。

具體的接口API函數整理如下:

三、ARM中的實現

我們以atomic_add為例,描述linux kernel中原子操作的具體代碼實現細節:

(1)ARMv6之前的CPU并不支持SMP,之后的ARM架構都是支持SMP的(例如我們熟悉的ARMv7-A)。因此,對于ARM處理,其原子操作分成了兩個陣營,一個是支持SMP的ARMv6之后的CPU,另外一個就是ARMv6之前的,只有單核架構的CPU。對于UP,原子操作就是通過關閉CPU中斷來完成的。

(2)這里的代碼和preloading cache相關。在strex指令之前將要操作的memory內容加載到cache中可以顯著提高性能。

(3)為了完整性,我還是重復一下匯編嵌入c代碼的語法:嵌入式匯編的語法格式是:asm(code : output operand list : input operand list : clobber list)。output operand list 和 input operand list是c代碼和嵌入式匯編代碼的接口,clobber list描述了匯編代碼對寄存器的修改情況。為何要有clober list?我們的c代碼是gcc來處理的,當遇到嵌入匯編代碼的時候,gcc會將這些嵌入式匯編的文本送給gas進行后續處理。這樣,gcc需要了解嵌入匯編代碼對寄存器的修改情況,否則有可能會造成大麻煩。例如:gcc對c代碼進行處理,將某些變量值保存在寄存器中,如果嵌入匯編修改了該寄存器的值,又沒有通知gcc的話,那么,gcc會以為寄存器中仍然保存了之前的變量值,因此不會重新加載該變量到寄存器,而是直接使用這個被嵌入式匯編修改的寄存器,這時候,我們唯一能做的就是靜靜的等待程序的崩潰。還好,在output operand list 和 input operand list中涉及的寄存器都不需要體現在clobber list中(gcc分配了這些寄存器,當然知道嵌入匯編代碼會修改其內容),因此,大部分的嵌入式匯編的clobber list都是空的,或者只有一個cc,通知gcc,嵌入式匯編代碼更新了condition code register。

大家對著上面的code就可以分開各段內容了。@符號標識該行是注釋。

這里的__volatile__主要是用來防止編譯器優化的。也就是說,在編譯該c代碼的時候,如果使用優化選項(-O)進行編譯,對于那些沒有聲明__volatile__的嵌入式匯編,編譯器有可能會對嵌入c代碼的匯編進行優化,編譯的結果可能不是原來你撰寫的匯編代碼,但是如果你的嵌入式匯編使用__asm__ __volatile__(嵌入式匯編)的語法格式,那么也就是告訴編譯器,不要隨便動我的嵌入匯編代碼哦。

(4)我們先看ldrex和strex這兩條匯編指令的使用方法。ldr和str這兩條指令大家都是非常的熟悉了,后綴的ex表示Exclusive,是ARMv7提供的為了實現同步的匯編指令。

LDREX , []

是base register,保存memory的address,LDREX指令從base register中獲取memory address,并且將memory的內容加載到(destination register)中。這些操作和ldr的操作是一樣的,那么如何體現exclusive呢?其實,在執行這條指令的時候,還放出兩條“狗”來負責觀察特定地址的訪問(就是保存在[]中的地址了),這兩條狗一條叫做local monitor,一條叫做global monitor。

STREX , , []

和LDREX指令類似,是base register,保存memory的address,STREX指令從base register中獲取memory address,并且將 (source register)中的內容加載到該memory中。這里的保存了memeory 更新成功或者失敗的結果,0表示memory更新成功,1表示失敗。STREX指令是否能成功執行是和local monitor和global monitor的狀態相關的。對于Non-shareable memory(該memory不是多個CPU之間共享的,只會被一個CPU訪問),只需要放出該CPU的local monitor這條狗就OK了,下面的表格可以描述這種情況

開始的時候,local monitor處于Open Access state的狀態,thread 1執行LDREX 命令后,local monitor的狀態遷移到Exclusive Access state(標記本地CPU對xxx地址進行了LDREX的操作),這時候,中斷發生了,在中斷handler中,又一次執行了LDREX ,這時候,local monitor的狀態保持不變,直到STREX指令成功執行,local monitor的狀態遷移到Open Access state的狀態(清除xxx地址上的LDREX的標記)。返回thread 1的時候,在Open Access state的狀態下,執行STREX指令會導致該指令執行失敗(沒有LDREX的標記,何來STREX),說明有其他的內核控制路徑插入了。

對于shareable memory,需要系統中所有的local monitor和global monitor共同工作,完成exclusive access,概念類似,這里就不再贅述了。

大概的原理已經描述完畢,下面回到具體實現面。

其中%3就是input operand list中的"r" (&v->counter),r是限制符(constraint),用來告訴編譯器gcc,你看著辦吧,你幫我選擇一個通用寄存器保存該操作數吧。%0對應output openrand list中的"=&r" (result),=表示該操作數是write only的,&表示該操作數是一個earlyclobber operand,具體是什么意思呢?編譯器在處理嵌入式匯編的時候,傾向使用盡可能少的寄存器,如果output operand沒有&修飾的話,匯編指令中的input和output操作數會使用同樣一個寄存器。因此,&確保了%3和%0使用不同的寄存器。

(5)完成步驟(4)后,%0這個output操作數已經被賦值為atomic_t變量的old value,毫無疑問,這里的操作是要給old value加上i。這里%4對應"Ir" (i),這里“I”這個限制符對應ARM平臺,表示這是一個有特定限制的立即數,該數必須是0~255之間的一個整數通過rotation的操作得到的一個32bit的立即數。這是和ARM的data-processing instructions如何解析立即數有關的。每個指令32個bit,其中12個bit被用來表示立即數,其中8個bit是真正的數據,4個bit用來表示如何rotation。更詳細的內容請參考ARM ARM文檔。

(6)這一步將修改后的new value保存在atomic_t變量中。是否能夠正確的操作的狀態標記保存在%1操作數中,也就是"=&r" (tmp)。

(7)檢查memory update的操作是否正確完成,如果OK,皆大歡喜,如果發生了問題(有其他的內核路徑插入),那么需要跳轉到lable 1那里,從新進行一次read-modify-write的操作。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 寄存器
    +關注

    關注

    31

    文章

    5336

    瀏覽量

    120232
  • cpu
    cpu
    +關注

    關注

    68

    文章

    10855

    瀏覽量

    211590
  • 函數
    +關注

    關注

    3

    文章

    4327

    瀏覽量

    62573

原文標題:Linux內核同步機制之(一):原子操作

文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    詳解linux內核中的mutex同步機制

    linux內核中,互斥量(mutex,即mutual exclusion)是一種保證串行化的睡眠鎖機制。和spinlock的語義類似,都是允許一個執行線索進入臨界區,不同的是當無法獲得鎖的時候
    的頭像 發表于 05-13 08:56 ?6846次閱讀
    詳解<b class='flag-5'>linux</b><b class='flag-5'>內核</b>中的mutex<b class='flag-5'>同步機制</b>

    Linux內核同步機制原子操作詳解

    系統調用的控制路徑上,完成讀操作之后,硬件觸發中斷,開始執行中斷處理函數。中斷處理函數的寫回操作被系統調用控制路徑上的寫回操作覆蓋了,導致結果不一致。
    發表于 06-26 16:04 ?713次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內核</b><b class='flag-5'>同步機制</b><b class='flag-5'>原子</b><b class='flag-5'>操作</b>詳解

    Linux內核同步機制mutex詳解

    linux內核中,互斥量mutex是一種保證CPU串行運行的睡眠鎖機制。和spinlock類似,都是同一個時刻只有一個線程進入臨界資源,不同的是,當無法獲取鎖的時候,spinlock原地自旋,而mutex則是選擇掛起當前線程,
    發表于 06-26 16:05 ?1112次閱讀

    Linux內核同步機制

    在現代操作系統里,同一時間可能有多個內核執行流在執行,因此內核其實象多進程多線程編程一樣也需要一些同步機制同步各執行單元對共享數據的訪問。
    發表于 08-06 07:08

    Vulkan同步機制和圖形轉換的風險

    Vulkan同步機制和圖形-計算-圖形轉換的風險(一)
    發表于 01-21 06:17

    RTT中的消息同步機制是如何實現的?

    RTT中的消息同步機制是如何實現的
    發表于 11-02 07:00

    linux內核機制有哪些

    路徑(進程)以交錯的方式運行。對于這些交錯路徑執行的內核路徑,如不采取必要的同步措施,將會對一些關鍵數據結構進行交錯訪問和修改,從而導致這些數據結構狀態的不一致,進而導致系統崩潰。因此,為了確保系統高效穩定有序地運行,linux
    發表于 11-14 15:25 ?5563次閱讀
    <b class='flag-5'>linux</b><b class='flag-5'>內核</b><b class='flag-5'>機制</b>有哪些

    linux內核機制

    在現代操作系統里,同一時間可能有多個內核執行流在執行,因此內核其實象多進程多線程編程一樣也需要一些同步機制同步各執行單元對共享數據的訪問。
    發表于 11-14 15:52 ?7115次閱讀

    你知道linux 同步機制的complete?

    Linux內核中,completion是一種簡單的同步機制,標志"things may proceed"。 要使用completion,必須在文件中包含,同時創建一個類型為struct completion的變量。
    發表于 04-24 11:45 ?1282次閱讀

    你了解Linux內核同步機制

    在現代操作系統里,同一時間可能有多個內核執行流在執行,因此內核其實象多進程多線程編程一樣也需要一些同步機制同步各執行單元對共享數據的訪問。
    發表于 05-12 08:26 ?633次閱讀

    可以了解并學習Linux 內核同步機制

    Linux內核同步機制,挺復雜的一個東西,常用的有自旋鎖,信號量,互斥體,原子操作,順序鎖,RCU,內存屏障等。
    發表于 05-14 14:10 ?700次閱讀

    Linux內核中有哪些鎖

    LInux操作系統里,同一時間可能有多個內核執行流在執行,因此內核其實象多進程多線程編程一樣也需要一些同步機制
    的頭像 發表于 02-24 15:26 ?3447次閱讀

    Linux內核同步機制

    在現代操作系統里,同一時間可能有多個內核執行流在執行,因此內核其實像多進程多線程編程一樣也需要一些同步機制同步各執行單元對共享數據的訪問,
    的頭像 發表于 09-22 09:46 ?2284次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內核</b>的<b class='flag-5'>同步機制</b>

    關于Linux kernel同步機制的這些知識點你不得不知道

    同步就是進程與進程之間,進程與系統資源之間的交互。由于 Linux內核采用的是多任務,所以在多個進程之間,必須要有同步機制來保證彼此協調。
    的頭像 發表于 04-21 14:42 ?820次閱讀

    淺談Linux kernel中的同步機制

    同步就是進程與進程之間,進程與系統資源之間的交互。由于 Linux內核采用的是多任務,所以在多個進程之間,必須要有同步機制來保證彼此協調。
    的頭像 發表于 05-04 17:06 ?904次閱讀
    主站蜘蛛池模板: 久久黄视频| 手机看片国产日韩欧美| 久草在线福利资站免费视频| 吃奶吸咪咪动态图| 国产国产乱老熟女视频网站97| 亚洲在线v观看免费国| 亚洲精品www久久久久久| 亚洲成人综合在线| 亚洲成年男人的天堂网| 亚洲精品天堂在线| 2019久久视频这里有精品15| 99RE8国产这里只有精品| 高干紧射H后入| 久久黄色网址| 久久精品国产午夜伦班片| 黑人巨大两根一起挤进欧美| 国内精品欧美久久精品| 国产人妖一区二区| 国产在线成人一区二区三区| 九九免费精品视频| 久青草国产在线视频亚瑟影视| 乱xxxjapanese黑人| 欧美特级特黄AAAAA片| 全彩无翼污之邪恶女教师| 特黄特色大片免费播放器试看| 跳蛋按摩棒玉势PLAY高H| 亚洲欧美视频在线| 999久久精品国产| 国产成人综合在线观看网站| 精品蜜臀AV在线天堂| 女人张开腿让男人桶爽免| 天天躁人人躁人人躁狂躁| 亚洲中文无码亚洲人在线观看- | 亚洲国产系列一区二区三区| 亚洲无人区码二码三码区别图| 69久久国产精品热88人妻| 东北成人社区| 麻豆高清免费国产一区| 午夜成a人片在线观看| 97精品免费视频| 国产在线精品亚洲二品区|