0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Linux內(nèi)核的內(nèi)存屏障的原理和用法分析

Linux閱碼場 ? 來源:Linux閱碼場 ? 作者:Linux閱碼場 ? 2022-09-05 09:13 ? 次閱讀

圈里流傳著一句話“珍愛生命,遠(yuǎn)離屏障”,這足以說明內(nèi)存屏障是一個相當(dāng)晦澀和難以準(zhǔn)確把握的東西。使用過弱的屏障,會導(dǎo)致軟件不穩(wěn)定。使用過強的屏障,會引起性能問題。所以工程上,追求恰到好處、不偏不倚的屏障。本文力求用最淺顯的語言,講清楚內(nèi)存屏障最晦澀的道理,本文也會給出五個工程案例,這些案例皆見于開源的代碼,不涉及任何組織和個人未公開的技術(shù)。

一、引子

我國古代著名程序猿韓愈曾經(jīng)寫下一個名為《春雪》的函數(shù):

新年都未有芳華,二月初驚見草芽。

白雪卻嫌春色晚,故穿庭樹作飛花。

這段代碼講述了一個關(guān)于memory reorder的故事,在計算機世界里面,冬天和春天并沒有明確的界限,明明已經(jīng)是春天了,但是還飄著冬天的雪。

下面我們看另外一段程序:

9453ff4a-2cb2-11ed-ba43-dac502259ad0.png

我們能確保c = 4嗎?實際上,任何一個角度都確定不了。比如CPU0上面a = 3是“下雪”,flag = 1是“春天”,a=3看似在flag=1之前,實際可能由于memory reorder的原因發(fā)生在flag = 1之后,所以flag即便已經(jīng)等于1,a也不一定等于3。

我們再退一萬步講,哪怕CPU0上面確實確保了春天不下雪,flag=1的時候a 100%就等于了3,那CPU1那邊就萬無一失了嗎?答案也是否定的,因為,在CPU1上面,即便我們的代碼是if(flag==1),接下來才做c=a+1,我們也不能確保a的load一定發(fā)生在flag==1之后。別忘了,CPU1會投機執(zhí)行,比如碰到if(flag==1)這種條件,CPU可能直接忽略,不管三七二十一,還是可能先執(zhí)行 load a, a+1的動作,然后反過來發(fā)現(xiàn)flag等于1,然后我認(rèn)為我的投機是成功的;即便投機失敗,CPU只需要保證load a, a+1的這些指令不retired就好。所以CPU1的load a, a+1完全可能發(fā)生在flag確切地等于1之前,因此即便CPU0保序了,CPU1仍然不能確保c=4。

我們看看CPU1在投機成功時候的行為邏輯和思想情感:

1. flag==1嗎?

2. 不知道??!我現(xiàn)在還沒讀出flag呢!

3. 管它呢,先假裝flag==1吧,投機一把,執(zhí)行l(wèi)oada, 把a+1看看

4.flag==1嗎?哇,它真地等于1,太爽了,load a和a+1已經(jīng)做完了。

如果投機失敗了呢?

1. flag==1嗎?

2.不知道?。∥椰F(xiàn)在還沒讀出flag呢!

3. 管它呢,先假裝flag==1吧,投機一把,執(zhí)行l(wèi)oada, 把a+1看看

4. flag==1嗎?Oh,shit,它不等于1,load a, a+1白做了.....

這就是弱序系統(tǒng)的典型特點。請問CPU為什么要這么“混亂”?這正是現(xiàn)代CPU為了保證高效執(zhí)行厲害的地方,但是也引入軟件使用上的復(fù)雜度。這種復(fù)雜度,類似于宋代著名程序媛李清照的函數(shù)《聲聲慢·尋尋覓覓》:“尋尋覓覓,冷冷清清,凄凄慘慘戚戚。乍暖還寒時候,最難將息。三杯兩盞淡酒,怎敵他、晚來風(fēng)急?雁過也,正傷心,卻是舊時相識。滿地黃花堆積,憔悴損,如今有誰堪摘?守著窗兒,獨自怎生得黑。梧桐更兼細(xì)雨,到黃昏、點點滴滴。這次第,怎一個愁字了得!”請問李清照童鞋說的究竟是春天還是秋天還是春天呢?據(jù)說至今也沒有人能夠解密。僅憑“乍暖還寒”一定會覺得是初春,但是你再繼續(xù)看到“雁過也”、“滿地黃花堆積”,這顯然又不是春天的景象。

罷了罷了,這一切都不重要了,重要的是,四季并不分明,四季沒有明確的界限。這是我們要牢記的第一個point!

二、屏障

正是因為四季沒有明確的界限,所以當(dāng)我們希望看到明確的順序的時候,我們希望引入一道屏障。讓冬天跑不到春天,讓春天跑不過去冬天。

典型的ARM64有這么幾種屏障:

a. DMB:Data Memory Barrier

b. DSB:Data Synchronization Barrier

c. ISB:Instruction Synchronization Barrier

d. LDAR(Load-Acquire)/STLR(Store-Release)

我們隨便打開ARM的手冊,看一個DMB的定義:

The Data Memory Barrier (DMB) prevents the reordering of specified explicit data accesses acrossthe barrier instruction. All explicit data load or store instructions, which are executed by the PEin program order before the DMB, are observed by all Observers within a specified Shareabilitydomain before the data accesses after the DMB in program order.

碼農(nóng)的內(nèi)心是崩潰的,人生已經(jīng)這么悲催了,你為什么還要拿這樣的繞口令來折磨我?什么叫“are observed by all Observers”?

下面我們給大家講述2只狗狗出家門的故事:

上圖的2只狗,首先在一個inner shareable domain里面,比如是自己的家門里面;然后是在一個outer shareable domain里面,比如是小區(qū)的出口;最后在太陽系里面。這2只小狗,出每一道門,都有observer可以看見它,有的observer是inner的(observer1),有的observer是outer的(observer2),有的observer屬于full system,比如天上的嫦娥(observer3)。

現(xiàn)在我們提出如下需求:

a. 黃狗狗出門后白狗狗出門。

b. 黃狗狗和白狗狗出門后,放煙霧消殺。

當(dāng)我們提出這樣的需求的時候,我們看3樣?xùn)|西:

1. 我們首先要看需要保證順序的2個事物的特征

在需求1里面,是2只特征一樣的東西,都是狗狗;在需求2里面,兩個事物之間一個是狗狗,一個是消殺的煙霧,顯然不是同類。

狗狗在硬件和Linux軟件層面上,可以理解為針對內(nèi)存的memory load/store指令;放煙霧,這種不屬于memory的load/store,比如你執(zhí)行的是tlbi、add加法或者寫的是ARM64系統(tǒng)寄存器(MSR指令),則顯然不屬于memory load/store。

這里就涉及到DMB和DSB的一個本質(zhì)區(qū)別,DMB針對的是memory的load/store之間;DSB強調(diào)的是同類或不同類事物的先后完成。

所以對于這個場景,我們正確的屏障是:

load黃狗狗

dmb ??

load白狗狗

dsb ??

MSR消毒煙霧

第一個是dmb,第2個是dsb。上面dmb和dsb后面都加了兩個“?”,證明這里有情況,什么情況?接著看。

2. 其次我們要看保序的observer在哪里

比如是家門口的小姑娘observer1(ISH,inner shareable)、還是小區(qū)門口的小姑娘observer2(OSH,outer shareable),還是天上的嫦娥呢(SY, Full System)?如果只是observer1看到黃狗狗先出門,白狗狗再出門,延遲顯然更小。在越大的訪問范圍保序,硬件的延遲越大。假設(shè)我們現(xiàn)在的保序需求是:

a. 小區(qū)門口(outer shareable)的observer2先看到黃狗狗出來,再看到白狗狗出來;

b. 家門口(inner shareable)的observer1先看到兩只狗狗出來,再看到放煙霧。

對于這個場景,我們正確的屏障是:

load黃狗狗

dmb OSH?

load白狗狗

dsb ISH?

MSR消毒煙霧

在DMB后面我們跟的是OSH,在DSB后面我們跟的是ISH,是因為observer的位置不一樣。注意,能用小observer的不用大observer。小區(qū)門口的observer,沒有透視眼+望遠(yuǎn)鏡,是看不到你家門口的狗狗的。

947dd98c-2cb2-11ed-ba43-dac502259ad0.png

在一個典型的ARM64系統(tǒng)里面,運行Linux的各個CPU在一個inner;而GPUDMA和CPU則同位于一個outer;當(dāng)然還有可能孤懸海外的一個Cortex-M3的MCU,盡管可以和CPU以某種方式通信,但是不太參與inner以及outer里面的總線interconnect。

3. 最后我們保序的方向是什么

前面我們只關(guān)心狗狗的出門(load),假設(shè)兩只狗狗都是進(jìn)門(store)呢?或者我們現(xiàn)在要求黃狗狗先進(jìn)門,白狗狗再出門呢?這個時候,我們要約束屏障的方向。

比如下面的代碼,約束了observer1(inner)先看到黃狗狗出門,再看到白狗狗出門:

load黃狗狗

dmb ISHLD

load白狗狗

比如下面的代碼,約束了observer2(outer)先看到黃狗狗進(jìn)門,再看到白狗狗進(jìn)門:

store黃狗狗

dmb OSHST

store白狗狗

這里我們看到一個用的是LD,一個用的是ST。我們再來看幾個栗子,它們都是干什么的:

a.A(load); dmb ISHLD; B; C(load/store)

保證Inner內(nèi),A和C的順序,只要A是load,無論C是load還是store;如果B既不是load也不是store,而是別的性質(zhì)的事情,則dmb完全管不到B;

b. A(load); dsb ISHLD; B; C(load/store)

保證Inner內(nèi),A和C的順序,只要A是load,無論C是load還是store;無論B是什么事情,inner都先到干完了A,再干B(注意這里是dsb啊,親)。

c. A(store); dmb ISHLD; B; C(store)

A,B,C三個東西完全亂序,因為dmb約束不了性質(zhì)不同的B,“LD”約束不了A和C的store順序。

d. A(store); dmb ISHST; B; C(store)

ST約束了A和C 2個東西在inner這里看起來是順序的,因為dmb約束不了B,所以B和A、C之間亂序。

注意上述4個屏障,由于都是ISH,故都不能保證observer2和observer3的順序,在observer2和3眼里,上述所有屏障,A、B、C都是亂序的。

另外,如果無論什么方向,我們都要保序,我們可以去掉LD和ST,這樣的保序方向是any-any。

到這里我們要牢記3個point:誰和誰保序;在哪里保序;朝哪個方向保序。

由此,我們可以清楚地看到DMB和DSB的區(qū)別,一個是保序內(nèi)存load,store;一個是保序內(nèi)存load,store + 其他指令。ISB的性質(zhì)會有很大的不同,ISB主要用于刷新處理器中的pipeline,因此可確保在 ISB 指令完成后,才從內(nèi)存系統(tǒng)中fetch位于該指令后的其他指令。比如你更新了代碼段的PTE,需要重新取指。而LDAR(Load-Acquire)/STLR(Store-Release)則是比較新的one-way barrier。如下圖,LDAR之前的LDR、STR可以跑到LDAR之后,但是不能跑到STLR之后;STLR之后的LDR,STR可以跑到STLR之前,但是不能跑到LDAR之前。所以STLR堵住了前面的往后面跑,LDAR堵住了后面的往前面跑。下面夾在LDAR和STLR之間的LDR,STR由于兩邊都是單向車道,而且都與它的行進(jìn)方向相反,所以它夾在死胡同里,哪里也去不了。

9491384c-2cb2-11ed-ba43-dac502259ad0.png

注意,LDAR和STLR與前面的dmb, dsb有本質(zhì)的不同,它本身是要跟地址的。比如現(xiàn)在家里有3只狗狗:

假設(shè)我們現(xiàn)在的要求是黃狗狗一定要在紅尾哈巴狗之后出門,而白狗狗什么時候出我們都不在乎,則代碼邏輯為:

ldr 白狗狗

ldar紅尾哈巴狗

ldr 黃狗狗

黃狗狗被紅尾哈巴狗的ldar擋住了,而白狗狗沒有被任何東西擋住,它可以:

1. 第一個出門

2. 紅尾哈巴狗出門后,黃狗狗出門前出門

3. 最后一個出門。

三、API

在Linux內(nèi)核,有4組經(jīng)典API:

SMP屏障

94bc375e-2cb2-11ed-ba43-dac502259ad0.png

此屏障主要用于運行Linux的多個核之間對內(nèi)存訪問的保序,所以它主要是dmb,它是ish,通過ld、st來區(qū)分保序的方向。

DMA屏障

94d30ab0-2cb2-11ed-ba43-dac502259ad0.png

此屏障主要用于運行Linux的多個核與DMA引擎之間的保序,所以它主要是dmb,它是osh,通過ld、st來區(qū)分保序的方向。

屏障

94e9ec44-2cb2-11ed-ba43-dac502259ad0.png

非常嚴(yán)格的完成屏障,mb()保證了前面的指令的完成,前面的指令不必是load,store,比如可以是TLBI。dsb(ld)、dsb(st)則要弱一點,分別保證前面的load,store執(zhí)行完了才執(zhí)行后面的指令。

load_acquire/store_release

邏輯通常是一種成對的__smp_load_acquire()、__smp_store_release()邏輯,特別適合2個或者多個CPU之間的鏈?zhǔn)奖P?。在ARM64里面用的是stlr,ldar實現(xiàn)如下:

950409da-2cb2-11ed-ba43-dac502259ad0.png

比如,下面的代碼邏輯,保證了CPU0、CPU1、CPU2這3個CPU在鏈條上保序訪問:

9520a978-2cb2-11ed-ba43-dac502259ad0.png

中間循環(huán)了一個鏈條邏輯,從而保證了這三個CPU中間內(nèi)存訪問的一些保序:

95334c54-2cb2-11ed-ba43-dac502259ad0.png

下面我們進(jìn)入五個工程實戰(zhàn),“熟讀唐詩三百首,不會吟詩也會吟”,最后我們會形成針對內(nèi)存屏障正確用法的語感,而全然忘記語法。

實戰(zhàn)一:運行Linux的多核通過中斷通信

95419cf0-2cb2-11ed-ba43-dac502259ad0.png

它的一般模式是:CPU0在DDR填入一段數(shù)據(jù),然后通過store指令寫INTR的寄存器向CPU1發(fā)送中斷。

store數(shù)據(jù)

barrier?

store intr寄存器

中間應(yīng)該用什么barrier?我們來回憶一下三要素:

a. 誰和誰保序?-> CPU0和CPU1這2個observer之間看到保序

b. 在哪里保序?-> 只需要CPU1看到CPU0寫入DDR和intr寄存器是保序的

c. 朝哪個方向保序?-> CPU0寫入一段數(shù)據(jù),然后寫入intr寄存器,只需要在st方向保序。

由此,我們得出結(jié)論,應(yīng)該使用的barrier是:dmb + ish + st,顯然就是smp_wmb。內(nèi)核代碼drivers/irqchip/irq-bcm2836.c也可以證實這一點:

955a9aca-2cb2-11ed-ba43-dac502259ad0.png

里面的注釋非常清晰,smp_wmb()保證了發(fā)起IPI之前,其他CPU應(yīng)該先觀察到內(nèi)存的數(shù)據(jù)在位。

現(xiàn)在我們把INTR換成gic-v3,就會變地tricky很多。gic-v3的IPI寄存器并不是映射到內(nèi)存空間的,而是一個sys寄存器,通過MSR來寫入。前面我們說過DMB只能搞定load/store之間,搞不定load/store與其他東西之間。

最開始的gic-v3驅(qū)動的作者其實也誤用了smp_wmb,造成了該驅(qū)動的穩(wěn)定性問題。于是Shanker Donthineni童鞋進(jìn)行了一個修復(fù),這個修復(fù)的commit如下:

956c41e4-2cb2-11ed-ba43-dac502259ad0.png

這個commit解釋了我們不能用dmb搞定memory和sysreg之間的事情,于是這個patch替換為了更強力的wmb(),那么這個替換是正確的嗎?

我們還是套一下三要素:

a. 誰和誰保序?-> CPU0和CPU1保序

b. 在哪里保序?-> 只需要CPU1看到CPU0寫入DDR后,再看到它寫sysreg

c. 朝哪個方向保序?-> CPU0寫入一段數(shù)據(jù),然后寫入sysreg寄存器,只需要在st方向保序。

我們要進(jìn)行保序的是CPU0和CPU1之間,顯然他們屬于inner。于是,我們得出正確的barrier應(yīng)該是:dsb + ish + st,wmb()屬于用力過猛了,因為wmb = dsb(st),保序范圍是full system?;诖耍P者再次在主線內(nèi)核對Shanker Donthineni童鞋的“修復(fù)”進(jìn)行了“修復(fù)”,縮小屏障的范圍,提升性能:

9593a112-2cb2-11ed-ba43-dac502259ad0.png

實戰(zhàn)二:寫入數(shù)據(jù)到內(nèi)存后,發(fā)起DMA

下面我們把需求變更為,CPU寫入一段數(shù)據(jù)后,寫Ethernet控制器與CPU之間的doorbell,發(fā)起DMA操作發(fā)包。

95b3c816-2cb2-11ed-ba43-dac502259ad0.png

我們還是套一下三要素:

a. 誰和誰保序?-> CPU和EMAC的DMA保序,DMA和CPU顯然不是inner

b. 在哪里保序?-> 只需要EMAC的DMA看到CPU寫入發(fā)包數(shù)據(jù)后,再看到它寫doorbell

c. 朝哪個方向保序?-> CPU寫入一段數(shù)據(jù),然后寫入doorbell,只需要在st方向保序。

于是,我們得出正確的barrier應(yīng)該是:dmb + osh + st,為什么是dmb呢,因為doorbell也是store寫的。我們來看看Yunsheng Lin童鞋的這個commit,它把用力過猛的wmb(),替換成了用writel()來寫doorbell:

95c1418a-2cb2-11ed-ba43-dac502259ad0.png

在ARM64平臺下,writel內(nèi)嵌了一個dmb + osh + st,這個從代碼里面可以看出來:

95d65296-2cb2-11ed-ba43-dac502259ad0.png

同樣的邏輯也可能發(fā)生在CPU與其他outer組件之間,比如CPU與ARM64的SMMU:

95e9ba5c-2cb2-11ed-ba43-dac502259ad0.png

實戰(zhàn)三:CPU與MCU通過共享內(nèi)存和hwspinlock通信

下面我們把場景變更為主CPU和另外一個cortex-m的MCU通過一片共享內(nèi)存通信,對這片共享內(nèi)存的訪問透過硬件里面自帶的hwspinlock(hardware spinlock)來解決。

9613ee8a-2cb2-11ed-ba43-dac502259ad0.png

我們想象CPU持有了hwspinlock,然后讀取對方cortex-m給它寫入共享內(nèi)存的數(shù)據(jù),并寫入一些數(shù)據(jù)到共享內(nèi)存,然后解鎖spinlock,通知cortex-m,這個時候cortex-m很快就可以持有鎖。

我們還是套一下三要素:

a. 誰和誰保序?-> CPU和Cortex-M保序

b. 在哪里保序?-> CPU讀寫共享內(nèi)存后,寫入hwspinlock寄存器解鎖,需要cortex-m看到同樣的順序

c. 朝哪個方向保序?-> CPU讀寫數(shù)據(jù),然后釋放hwspinlock,我們要保證,CPU的寫入對cortex-m可見;我們同時要保證,CPU放鎖前的共享內(nèi)存讀已經(jīng)完成,如果我們不能保證解鎖之前CPU的讀已經(jīng)完成,cortex-m很可能馬上寫入新數(shù)據(jù),然后CPU讀到新的數(shù)據(jù)。所以這個保序是雙向的。

Talk is cheap, show me the code:

962c50f6-2cb2-11ed-ba43-dac502259ad0.png

里面用的是mb(),這是一個dsb+full system+ld+st,讀代碼的注釋也是一種享受。

實戰(zhàn)四:SMMU與CPU通過一個queue通信

現(xiàn)在我們把場景切換為,SMMU與CPU之間,通過一片放入共享內(nèi)存的queue來通信,比如SMMU要通知CPU一些什么event,它會把event放入queue,放完了SMMU會更新另外一個pointer內(nèi)存,表示queue增長到哪里了。

963a3478-2cb2-11ed-ba43-dac502259ad0.png

然后CPU通過這樣的邏輯來工作

964add00-2cb2-11ed-ba43-dac502259ad0.png

這是一種典型的控制依賴,而控制依賴并不能被硬件自動保序,CPU完全可以在if(pointer滿足什么條件)滿足之前,投機load了queue的內(nèi)容,從而load到了錯誤的queue內(nèi)容。

我們還是套一下三要素:

a.誰和誰保序?-> CPU和SMMU保序

b.在哪里保序?-> 要保證CPU先讀取SMMU的pointer后,再讀取SMMU寫入的queue;

c.朝哪個方向保序?-> CPU讀pointer,再讀queue內(nèi)容,在load方向保序

于是,我們得出正確的barrier應(yīng)該是:dmb + osh + ld,我們來看看wangzhou童鞋的這個修復(fù):

9659e8e0-2cb2-11ed-ba43-dac502259ad0.png

ARM64平臺的readl()也內(nèi)嵌了dmb + osh + ld屏障。顯然這個修復(fù)的價值是非常大的,這是一個由弱變強的過程。前面我們說過,由強變?nèi)跏切阅軉栴},而由弱變強則往往修復(fù)的是穩(wěn)定性問題。也就是這種用錯了弱barrier的場景,往往bug非常難再現(xiàn),需要很長時間的測試才再現(xiàn)一次。

實戰(zhàn)五:修改頁表PTE后刷新tlb

現(xiàn)在我們的故事演變成了,CPU0修改了頁表PTE,然后通知其他所有CPU,PTE應(yīng)該被更新,其他CPU需要刷新TLB。

966f55fe-2cb2-11ed-ba43-dac502259ad0.png

它的一般流程是CPU調(diào)用set_pte_at()修改了內(nèi)存里面的PTE,然后進(jìn)行tlbi等動作。這里就變地非常復(fù)雜了:

9682ed08-2cb2-11ed-ba43-dac502259ad0.png

我們看看barrier1,它在屏障store和tlbi之間,由于二者一個是狗狗,一個是消殺煙霧,顯然不能是dmb,只能是dsb;我們需要CPU1看到set_pte_at的動作先于tlbi的動作,所以這個屏障的范圍應(yīng)該是ISH;由于屏障需要保障的是set_pte_at的store,而不是load,所以方向是st,由此我們得出第一個barrier應(yīng)該是:dsb + ish + st。

詳細(xì)的流程我們可以參考下如下代碼:

9691cad0-2cb2-11ed-ba43-dac502259ad0.png

barrier2用的是dsb(ish),它保證了inner內(nèi)的CPU都先看到了tlbi的完成;barrier3用的isb(),它保證了CPU fetch到PTE修正之后的指令。

結(jié)語

本文對Linux內(nèi)核的內(nèi)存屏障的原理和用法進(jìn)行一些分析和實戰(zhàn),它并未覆蓋內(nèi)存屏障的全部知識,但是應(yīng)該可應(yīng)付工程里面90%以上的迷惘和困惑。由于作者水平有限,文中疏漏與錯誤在所難免,懇請讀者朋友們海涵。本文完成之時,北半球正在告別烈日炙烤的夏季,南半球即將迎來姹紫嫣紅的春天,愿所有人都有一個美好的未來。

審核編輯:彭靜
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    10863

    瀏覽量

    211781
  • 內(nèi)存
    +關(guān)注

    關(guān)注

    8

    文章

    3025

    瀏覽量

    74056
  • 軟件
    +關(guān)注

    關(guān)注

    69

    文章

    4944

    瀏覽量

    87500
  • LINUX內(nèi)核
    +關(guān)注

    關(guān)注

    1

    文章

    316

    瀏覽量

    21651

原文標(biāo)題:原理和實戰(zhàn)解析Linux中如何正確地使用內(nèi)存屏障

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

收藏 人收藏

    評論

    相關(guān)推薦

    從硬件引申出內(nèi)存屏障,帶你深入了解Linux內(nèi)核RCU

    本文從硬件的角度引申出內(nèi)存屏障,這不是內(nèi)存屏障的詳盡手冊,但是相關(guān)知識對于理解RCU有所幫助。
    的頭像 發(fā)表于 09-19 11:39 ?6140次閱讀
    從硬件引申出<b class='flag-5'>內(nèi)存</b><b class='flag-5'>屏障</b>,帶你深入了解<b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>RCU

    Linux內(nèi)存管理是什么,Linux內(nèi)存管理詳解

    Linux內(nèi)存管理 Linux內(nèi)存管理是一個非常復(fù)雜的過程,主要分成兩個大的部分:內(nèi)核內(nèi)存
    的頭像 發(fā)表于 05-11 17:54 ?6064次閱讀
    <b class='flag-5'>Linux</b>的<b class='flag-5'>內(nèi)存</b>管理是什么,<b class='flag-5'>Linux</b>的<b class='flag-5'>內(nèi)存</b>管理詳解

    Linux內(nèi)核內(nèi)存映射原理分析

    Linux 內(nèi)核采用延遲分配物理內(nèi)存的策略,在進(jìn)程第一次訪問虛擬頁的時候,產(chǎn)生缺頁異常。如果是文件映射,那么分配物理頁,把文件指定區(qū)間的數(shù)據(jù)讀到物理頁中,然后在頁表中把虛擬頁映射到物理頁;如果是匿名映射,那么分配物理頁,然后在頁
    發(fā)表于 07-21 17:06 ?2356次閱讀

    ARM體系結(jié)構(gòu)之內(nèi)存序與內(nèi)存屏障

    本文介紹 Armv8-A 架構(gòu)的內(nèi)存序模型,并介紹 arm 的各種內(nèi)存屏障。本文還會指出一些需要明確內(nèi)存保序的場景,并指明如何使用內(nèi)存
    發(fā)表于 06-15 18:19 ?1714次閱讀
    ARM體系結(jié)構(gòu)之<b class='flag-5'>內(nèi)存</b>序與<b class='flag-5'>內(nèi)存</b><b class='flag-5'>屏障</b>

    Linux內(nèi)核內(nèi)存泄漏怎么辦

    Linux內(nèi)核開發(fā)中,Kmemleak是一種用于檢測內(nèi)核內(nèi)存泄漏的工具。
    發(fā)表于 07-04 11:04 ?824次閱讀

    Linux內(nèi)核內(nèi)存管理架構(gòu)解析

    內(nèi)存管理子系統(tǒng)可能是linux內(nèi)核中最為復(fù)雜的一個子系統(tǒng),其支持的功能需求眾多,如頁面映射、頁面分配、頁面回收、頁面交換、冷熱頁面、緊急頁面、頁面碎片管理、頁面緩存、頁面統(tǒng)計等,而且對性能也有很高
    的頭像 發(fā)表于 01-04 09:24 ?667次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b><b class='flag-5'>內(nèi)存</b>管理架構(gòu)解析

    Linux內(nèi)核地址映射模型與Linux內(nèi)核高端內(nèi)存詳解

    Linux 操作系統(tǒng)和驅(qū)動程序運行在內(nèi)核空間,應(yīng)用程序運行在用戶空間,兩者不能簡單地使用指針傳遞數(shù)據(jù),因為Linux使用的虛擬內(nèi)存機制,用戶空間的數(shù)據(jù)可能被換出,當(dāng)
    發(fā)表于 05-08 10:33 ?3457次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>地址映射模型與<b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>高端<b class='flag-5'>內(nèi)存</b>詳解

    導(dǎo)致ARM內(nèi)存屏障的原因究竟有哪些

    與程序員的代碼邏輯不符,導(dǎo)致一些錯誤的發(fā)生,為了保證內(nèi)存訪問的一致性,也是保證程序的正確性,使用內(nèi)存屏障來保證內(nèi)存的訪問順序。ARM采用的是弱一致性
    發(fā)表于 05-09 09:32

    內(nèi)存屏障機制及內(nèi)核相關(guān)源代碼分析

    內(nèi)存屏障Linux Kernel中常要遇到的問題,這里專門來對其進(jìn)行研究。一者查閱網(wǎng)上現(xiàn)有資料,進(jìn)行整理匯集;二者翻閱Linux內(nèi)核方面的
    發(fā)表于 04-03 20:57 ?14次下載

    內(nèi)存屏障是什么

    內(nèi)存屏障,也稱內(nèi)存柵欄,內(nèi)存柵障,屏障指令等, 是一類同步屏障指令,是CPU或編譯器在對
    發(fā)表于 11-14 09:43 ?6531次閱讀
    <b class='flag-5'>內(nèi)存</b><b class='flag-5'>屏障</b>是什么

    高端內(nèi)存的詳解:linux用戶空間與內(nèi)核空間

    Linux 操作系統(tǒng)和驅(qū)動程序運行在內(nèi)核空間,應(yīng)用程序運行在用戶空間,兩者不能簡單地使用指針傳遞數(shù)據(jù),因為Linux使用的虛擬內(nèi)存機制,用戶空間的數(shù)據(jù)可能被換出,當(dāng)
    發(fā)表于 04-28 17:33 ?994次閱讀
    高端<b class='flag-5'>內(nèi)存</b>的詳解:<b class='flag-5'>linux</b>用戶空間與<b class='flag-5'>內(nèi)核</b>空間

    可以了解并學(xué)習(xí)Linux 內(nèi)核的同步機制

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

    干貨:Linux內(nèi)核中等待隊列的四個用法

    Linux內(nèi)核里的等待隊列機制在做驅(qū)動開發(fā)時用的非常多,多用來實現(xiàn)阻塞式訪問,下面簡單總結(jié)了等待隊列的四種用法,希望對讀者有所幫助。
    的頭像 發(fā)表于 06-20 09:59 ?2850次閱讀

    Linux內(nèi)核源碼分析-進(jìn)程的哪些內(nèi)存類型容易引起內(nèi)存泄漏?

    Linux內(nèi)核主要學(xué)習(xí)內(nèi)容可以分為三大塊:進(jìn)程、內(nèi)存及協(xié)議棧。今天就說說內(nèi)存泄露的問題。相信你在平時的工作中,應(yīng)該遇到過下面這些場景: 伴隨著服務(wù)器中的后臺任務(wù)持續(xù)地運行,系統(tǒng)中可用
    發(fā)表于 01-14 13:02 ?6次下載
    <b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>源碼<b class='flag-5'>分析</b>-進(jìn)程的哪些<b class='flag-5'>內(nèi)存</b>類型容易引起<b class='flag-5'>內(nèi)存</b>泄漏?

    Linux內(nèi)核引導(dǎo)內(nèi)存分配器的原理

    Linux內(nèi)核引導(dǎo)內(nèi)存分配器使用的是伙伴系統(tǒng)算法。這種算法是一種用于動態(tài)內(nèi)存分配的高效算法,它將內(nèi)存空間劃分為大小相等的塊,然后將這些塊組合
    發(fā)表于 04-03 14:52 ?411次閱讀