Linux核心中的記憶體屏障

2021-08-19 11:37:52 字數 1894 閱讀 3322

編譯器有時會對**做一些優化,例如嘗試在保證程式執行正確的前提下修改指令順序或優化ldr/str指令,讓程式執行地更快。但是編譯器畢竟不能完全猜透人的心思,有時候它做的優化會導致程式執行不符我們的預期。

因此,核心中提供了一些額外的函式,可以插在某段**裡,告訴編譯器不要在這裡做指令優化。這些函式分為兩種:

記憶體屏障:rmb(), wmb(), mb(),可以防止硬體上的指令重排。除了編譯器,有的cpu也支援對指令進行重排來優化程式執行效率,這幾個函式就是去防止cpu去做這些事情。rmb()是讀訪問記憶體屏障,它保證在屏障(呼叫rmb()的位置處)之後的任何讀操作在執行之前,屏障之前的所有讀操作都已經完成。wmb()對應寫操作,意思同上。mb()就同時包含讀和寫操作,意思同上。

優化屏障:barrier(),防止編譯器對記憶體訪問的優化,類似volatile關鍵字對於訪問變數的作用。它告訴編譯器,在插入barrier()的位置處,記憶體中的內容都被更新了,你想讀變數、對映到記憶體的暫存器等內容都需要真正到記憶體裡去讀,這樣就能保證barrier之後的讀指令不會被優化掉。

上面第1種屏障是和硬體即cpu特性相關的,那麼,如果你的cpu沒有指令重排的能力,也就沒有必要防止指令重排了。例如,一款cpu不支援寫指令重排,那麼系統中的wmb()就直接被定義成了barrier()。

還有smp系統中使用的smp_rmb(), smp_wmb(), smp_mb(),它們只用於smp系統。在單處理器上它們被定義成barrier()。

當然,防止優化後,受影響的**執行效率會降低,但為了保證正確性,犧牲一點效能是值得的。

優化屏障的乙個特定應用是核心的搶占機制。我們看到preempt_disable()/preempt_enable()並不是簡單的修改搶占計數:

#define preempt_disable() \

do while (0)

#define preempt_enable_no_resched() \

do while (0)

#define preempt_enable() \

do while (0)

正常的用法我們都很熟悉:

preempt_disable()

//臨界區,不能被搶占。

preempt_enable()

但如果不加屏障,誰也不知道編譯器是否會優化成這樣:

//臨界區,不能被搶占。

preempt_disable()

preempt_enable()

preempt_disable()

preempt_enable()

//臨界區,不能被搶占。

這樣臨界區**就沒有受到保護。因此,需要在關搶占時增加preempt_count之後增加乙個屏障,告訴編譯器在這之前要完成寫請求,接著再執行臨界區**,在開搶占時遞減preempt_count之前增加乙個屏障,告訴編譯器要真正去記憶體裡獲取這個值,不能偷懶。

volatile:

上面提到了volatile,我也簡單說一下,volatile的作用是防止編譯器對訪存指令做優化,例如,在乙個執行緒的一段**裡要定期讀乙個變數a,根據讀到的不同值做不同事情,但這個a的修改是在另乙個執行緒裡做的,那編譯器可能就認為a沒有被改過從而不是去每次從記憶體裡去讀新的a(把a放在乙個臨時暫存器裡,每次讀暫存器)。

用volatile關鍵字修飾a的作用就是讓使用a的**每次都真正從記憶體裡去讀。volatile的作用僅此而已(沒***原子性之類的作用,保證原子性該加鎖還是要加鎖)。

核心中與驅動相關的記憶體操作之十 記憶體屏障

雖然實際驅動中不常用 但是閱讀核心比較深層的 經常會遇到 為什麼存在記憶體屏障呢 先看一下下面的場景 編譯器和處理器為了提高效率 可能對讀和寫操作重新進行了排序,例如 在某些處理器上 以下 a 1 b 2 有可能在 a中存放新值之前就在 b中存放新值.但是,我們在操作記憶體或者和硬體互動時 常常需要...

Linux記憶體屏障

首先這裡有一篇文章介紹記憶體屏障的,寫的挺好的,可以看看 linux記憶體屏障是用來解決指令亂序的問題。什麼是指令的亂序呢?簡單一點說就是本來 裡面是這麼寫的 instruction a intstuction b 結果在cpu上執行變成了 instruction b instruction a 導...

Linux核心中記憶體分配函式

1.原理說明 linux核心中採 用了一種同時適用於32位和64位系統的內 存分頁模型,對於32位系統來說,兩級頁表足夠用了,而在x86 64系 統中,用到了四級頁表,如圖2 1所示。四級頁表分別為 頁全域性目錄 page global directory 頁上級目錄 page upper dire...