由preempt disable的實現想到的

2021-05-23 21:54:49 字數 1397 閱讀 8055

#define preempt_disable() /

do while (0)

實現很簡單,就兩行**,第一行把程序描述符中的preempt_count加1,第二行加乙個優化屏障。展開inc_preempt_count()後就是:

current->thread_info->preempt_count++;

barrier();

看到這個實現的時候,覺的很奇怪,用個優化屏障就夠了嗎?似乎應該用記憶體屏障mb()。優化屏障只能保證編譯器不亂排指令,而如果cpu亂序執行,被preempt_disable保護的臨界區中的指令豈不是有可能在preempt_count++之前執行。但可以肯定這不是個bug,這麼重要的地方不可能出現這麼低階的bug。那麼就結合preempt_disable的應用環境分析一下,以下為個人的分析,並未得到權威認證,如有錯誤還請指正。

既然沒有bug,那只能有兩種可能,第一就是禁用搶占後臨界區中的指令,不會先於preempt_count++執行。第二就是在臨界區中的指令先執行且preempt_count++尚未執行的時候,不能發生搶占或者搶占不會有問題。第一種情況由於cpu的亂序執行顯然無法保證。那麼只能是第二種。為什麼呢?接著分析。

核心搶占發生在硬體中斷喚醒乙個高優先順序任務的時候,當發現當前任務的優先順序低於被喚醒的任務的優先順序且當前任務的preempt_count為0,那麼就會搶占當前任務。因此硬體中斷是導火索,也就是說只有在臨界區中的指令執行後,preempt_count++未執行前發生乙個硬體中斷,才有可能發生搶占。但是硬體中斷都是precise interrupt,精確中斷,即中斷發生時的pc指標記錄的指令之前的指令都已完成,之後的指令都未執行。這樣即使在上述情況發生乙個硬體中斷,硬體只能有兩種方法來保證中斷的精確性:

1. 丟棄臨界區中指令的執行結果,將pc指標指向preempt_disable()。這樣即使被搶占,臨界區中的指令的執行結果也被丟棄了,所以不會出問題。

2. 等preempt_disable()指令執行後,將pc指標指向臨界區中最後完成的指令的下一條指令。這樣由於preempt_count被加1了,該任務就不能被搶占了,所以也不會出問題。

分析到這裡,可以看出此處確實不需要記憶體屏障了,用barrier()保證編譯器不亂排臨界區中的指令就可以了。但是實際上這裡這個barrier()還有另外乙個作用,就是保證編譯器會產生寫記憶體的指令,把preempt_count的值寫到記憶體。否則編譯器可能對preempt_count進行優化,僅僅把更新後的值放到暫存器中。這樣會出問題,比如在臨界區中產生乙個中斷,中斷處理程式只能從記憶體中去讀preempt_count的值,它可能無法看到核心搶占已經被禁止,而錯誤的將不能被搶占的任務搶占。這是中斷和程序共享資料時用barrier()來保持同步而不用鎖的乙個很好的例子。

終於分析完了,不由的感嘆,核心真是太精妙了,簡單的兩行**,隱藏著這麼深的問題。要想成為linux hacker,要走的路還有很長,努力吧。

由內而外,相由心生

我們看乙個人,可以看他的相,但是不要完全就這個相來論這個人,不要我們第一眼看過去看他什麼,看他的眼睛,乙個人眼睛呢他露了凶光,他很 這個人你就要一定小心,他眼睛很暗淡,他沒有什麼力量更談不上有什麼神,這個人運氣不會好,我講這些跟迷信沒有一點關係,沒有,因為他是你內心在外面的乙個表現,我在說一遍啊,人...

由PageRank想到的

首先來看看什麼是pagerank pagerank 技術 通過對由超過 50,000 萬個變數和 20 億個詞彙組成的方程進行計算,pagerank 能夠對網頁的重要性做出客觀的評價。pagerank 並不計算直接鏈結的數量,而是將從網頁 a 指向網頁 b 的鏈結解釋為由網頁 a 對網頁 b 所投的...

由Cannot find file 想到的

記錄一下 今天除錯程式,單步真機除錯,我日,程式一步一步走,盡然和程式根本就對不上號。特別奇怪。思考一下,應該是工程太多太雜,自己有不小心,讓它們混在一起打架了。於是繼續,把其它所有工程都關了,只開啟乙個,清理了所有工程。與此工程有關的直接搜尋清理,一直以來覺得沒有必要,但這次是為了保險起見。編譯工...