日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux内核ARM构架中原子变量的底层实现研究

發布時間:2023/12/19 linux 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux内核ARM构架中原子变量的底层实现研究 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?前段時間重新研究了一下Linux的并發控制機制,對于內核的自旋鎖、互斥鎖、信號量等機制及其變體做了底層代碼上的研究。因為只有從原理上理解了這些機制,在編寫驅動的時候才會記得應該注意什么。這些機制基本都從代碼上理解了,但是唯有一個不是非常理解的是內核對于ARM構架中原子變量的底層支持,這個機制其實在自旋鎖、互斥鎖以及讀寫鎖等內核機制中都有類似的使用。這里將學習的結果寫出,請大家指正。

? ? 假設原子變量的底層實現是由一個匯編指令實現的,這個原子性必然有保障。但是如果原子變量的實現是由多條指令組合而成的,那么對于SMP和中斷的介入會不會有什么影響呢?我在看ARM的原子變量操作實現的時候,發現其是由多條匯編指令(ldrex/strex)實現的。在參考了別的書籍和資料后,發現大部分書中對這兩條指令的描訴都是說他們是支持在SMP系統中實現多核共享內存的互斥訪問。但在UP系統中使用,如果ldrex/strex和之間發生了中斷,并在中斷中也用ldrex/strex操作了同一個原子變量會不會有問題呢?就這個問題,我認真看了一下內核的ARM原子變量源碼和ARM官方對于ldrex/strex的功能解釋,總結如下:

?

一、ARM構架的原子變量實現結構

? ? 對于ARM構架的原子變量實現源碼位于:arch/arm/include/asm/atomic.h

? ? 其主要的實現代碼分為ARMv6以上(含v6)構架的實現和ARMv6版本以下的實現。

該文件的主要結構如下:

  • #if?__LINUX_ARM_ARCH__?>=?6

  • ......(通過ldrex/strex指令的匯編實現)

  • #else?/*?ARM_ARCH_6?*/

  • #ifdef CONFIG_SMP
  • #error?SMP?not?supported?on?pre-ARMv6 CPUs
  • #endif

  • ......(通過關閉CPU中斷的C語言實現)

  • #endif?/*?__LINUX_ARM_ARCH__?*/
  • ......?

  • ?#ifndef CONFIG_GENERIC_ATOMIC64

  • ......(通過ldrexd/strexd指令的匯編實現的64bit原子變量的訪問)

  • #else?/*?!CONFIG_GENERIC_ATOMIC64?*/

  • #include?<asm-generic/atomic64.h>

  • #endif

  • #include?<asm-generic/atomic-long.h>
  • ? ? ??這樣的安排是依據ARM核心指令集版本的實現來做的:

    (1)在ARMv6以上(含v6)構架有了多核的CPU,為了在多核之間同步數據和控制并發,ARM在內存訪問上增加了獨占監測(Exclusive monitors)機制(一種簡單的狀態機),并增加了相關的ldrex/strex指令。請先閱讀以下參考資料(關鍵在于理解local monitor和Global monitor):

    1.2.2.?Exclusive monitors

    4.2.12.?LDREX??STREX

    (2)對于ARMv6以前的構架不可能有多核CPU,所以對于變量的原子訪問只需要關閉本CPU中斷即可保證原子性。?

    對于(2),非常好理解。

    但是(1)情況,我還是要通過源碼的分析才認同這種代碼,以下我僅僅分析最具有代表性的atomic_add源碼,其他的API原理都一樣。如果讀者還不熟悉C內嵌匯編的格式,請參考ARM GCC?內嵌匯編手冊》

    ?

    二、內核對于ARM構架的atomic_add源碼分析


  • /*
  • *?ARMv6 UP 和 SMP 安全原子操作。 我們是用獨占載入和
  • *?獨占存儲來保證這些操作的原子性。我們可能會通過循環
  • *?來保證成功更新變量。
  • */

  • static inline void atomic_add(int?i,?atomic_t?*v)
  • {
  • unsigned long tmp;
  • int?result;
  • __asm__ __volatile__("@ atomic_add\n"
  • "1: ldrex %0, [%3]\n"
  • " add %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");
  • }
  • 源碼分析:?

    注意:根據內聯匯編的語法,result、tmp、&v->counter對應的數據都放在了寄存器中操作。如果出現上下文切換,切換機制會做寄存器上下文保護。

    ?(1)ldrex %0, [%3]

    意思是將&v->counter指向的數據放入result中,并且(分別在Local monitor和Global monitor中)設置獨占標志。

    (2)add %0, %0, %4

    result = result + i

    (3)strex %1, %0, [%3]

    意思是將result保存到&v->counter指向的內存中,此時?Exclusive monitors會發揮作用,將保存是否成功的標志放入tmp中。

    (4)?teq %1, #0

    測試strex是否成功(tmp == 0???)

    (5)bne 1b

    如果發現strex失敗,從(1)再次執行。

    ? ? ??通過上面的分析,可知關鍵在于strex的操作是否成功的判斷上。而這個就歸功于ARM的Exclusive monitors和ldrex/strex指令的機制。以下通過可能的情況分析ldrex/strex指令機制。(請閱讀時參考4.2.12.?LDREX??STREX

    ?

    1、UP系統或SMP系統中變量為非CPU間共享訪問的情況?

    ? ? 此情況下,僅有一個CPU可能訪問變量,此時僅有Local monitor需要關注。

    ? ? 假設CPU執行到(2)的時候,來了一個中斷,并在中斷里使用ldrex/strex操作了同一個原子變量。則情況如下圖所示:

    • A:處理器標記一個物理地址,但訪問尚未完畢
    • B:再次標記此物理地址訪問尚未完畢(與A重復)
    • C:進行存儲操作,清除以上標記,返回0(操作成功)
    • D:不會進行存儲操作,并返回1(操作失敗)?

    也就是說,中斷例程里的操作會成功,被中斷的操作會失敗重試。?

    ?

    2、SMP系統中變量為CPU間共享訪問的情況

    ??

    ? ? 此情況下,需要兩個CPU間的互斥訪問,此時ldrex/strex指令會同時關注Local monitor和Global monitor。

    (i)兩個CPU同時訪問同個原子變量(ldrex/strex指令會關注Global monitor。)

    • A:將該物理地址標記為CPU0獨占訪問,并清除CPU0對其他任何物理地址的任何獨占訪問標記。
    • B:標記此物理地址為CPU1獨占訪問,并清除CPU1對其他任何物理地址的任何獨占訪問標記。
    • C:沒有標記為CPU0獨占訪問,不會進行存儲,并返回1(操作失敗)。
    • D:已被標記為CPU1獨占訪問,進行存儲并清除獨占訪問標記,并返回0(操作成功)。

    ?也就是說,后執行ldrex操作的CPU會成功。

    ?

    (ii)同一個CPU因為中斷,“嵌套”訪問同個原子變量(ldrex/strex指令會關注Local monito)

    • A:將該物理地址標記為CPU0獨占訪問,并清除CPU0對其他任何物理地址的任何獨占訪問標記。
    • B:再次標記此物理地址為CPU0獨占訪問,并清除CPU0對其他任何物理地址的任何獨占訪問標記。
    • C:已被標記為CPU0獨占訪問,進行存儲并清除獨占訪問標記,并返回0(操作成功)。
    • D:沒有標記為CPU0獨占訪問,不會進行存儲,并返回1(操作失敗)。

    也就是說,中斷例程里的操作會成功,被中斷的操作會失敗重試。

    ?

    (iii)兩個CPU同時訪問同個原子變量,并同時有CPU因中斷“嵌套”訪問改原子變量(ldrex/strex指令會同時關注Local monitor和Global monitor)

    雖然對于人來說,這種情況比較BT。但是在飛速運行的CPU來說,BT的事情隨時都可能發生。

    • A:將該物理地址標記為CPU0獨占訪問,并清除CPU0對其他任何物理地址的任何獨占訪問標記。
    • B:標記此物理地址為CPU1獨占訪問,并清除CPU1對其他任何物理地址的任何獨占訪問標記。
    • C:再次標記此物理地址為CPU0獨占訪問,并清除CPU0對其他任何物理地址的任何獨占訪問標記。
    • D:已被標記為CPU0獨占訪問,進行存儲并清除獨占訪問標記,并返回0(操作成功)。
    • E:沒有標記為CPU1獨占訪問,不會進行存儲,并返回1(操作失敗)。
    • F:沒有標記為CPU0獨占訪問,不會進行存儲,并返回1(操作失敗)。

    ?

    ? ? 當然還有其他許多復雜的可能,也可以通過ldrex/strex指令的機制分析出來。從上面列舉的分析中,我們可以看出:ldrex/strex可以保證在任何情況下(包括被中斷)的訪問原子性。所以內核中ARM構架中的原子操作是可以信任的。

    總結

    以上是生活随笔為你收集整理的Linux内核ARM构架中原子变量的底层实现研究的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。