輕量級 PI-futexes

我們將它們稱為輕量級,原因有三:

  • 在使用者空間快速路徑中,啟用 PI 的 futex 完全不涉及核心工作(或任何其他 PI 複雜性)。無需註冊,無需額外的核心呼叫 - 只是使用者空間中的純粹快速原子操作。

  • 即使在慢速路徑中,系統呼叫和排程模式也與普通 futex 非常相似。

  • 核心中的 PI 實現圍繞互斥鎖抽象進行精簡,並具有嚴格的規則,以保持實現相對簡單:只有一個所有者可以擁有鎖(即不支援讀寫鎖),只有所有者可以解鎖鎖,沒有遞迴鎖定等等。

優先順序繼承 - 為什麼?

簡短的回答:使用者空間 PI 有助於實現/改進使用者空間應用程式的確定性。在最佳情況下,它可以幫助實現確定性和良好界定的延遲。即使在最壞的情況下,PI 也會改善與鎖定相關的應用程式延遲的統計分佈。

更長的回覆

首先,在多個任務之間共享鎖是一種常見的程式設計技術,通常無法用無鎖演算法代替。正如我們在核心中看到的那樣[它本身就是一個相當複雜的程式],無鎖結構更像是例外而不是規範 - 當前共享資料結構的無鎖與鎖定程式碼的比率約為 1:10 到 1:100。無鎖很難,並且無鎖演算法的複雜性常常危及對所述程式碼進行穩健審查的能力。也就是說,關鍵的 RT 應用程式通常選擇鎖定結構來保護關鍵資料結構,而不是無鎖演算法。此外,在某些情況下(如共享硬體或其他資源限制),無鎖訪問在數學上是不可能的。

媒體播放器(如 Jack)就是一個合理的應用程式設計的例子,其中多個任務(具有多個優先順序)共享短時間持有的鎖:例如,高優先順序音訊播放執行緒與中優先順序構造音訊資料執行緒和低優先順序顯示顏色執行緒相結合。如果再加上影片和解碼,我們就有了更多的優先順序。

因此,一旦我們接受同步物件(鎖)是生活中不可避免的事實,並且一旦我們接受多工使用者空間應用程式對能夠使用鎖抱有非常合理的期望,我們就必須考慮如何為使用者空間提供確定性鎖定實現的選項。

大多數反對進行優先順序繼承的技術反駁只適用於核心空間鎖。但是使用者空間鎖是不同的,我們無法在臨界區停用中斷或使任務不可搶佔,因此“使用自旋鎖”的論點不適用(使用者空間自旋鎖與其他使用者空間鎖定結構具有相同的優先順序反轉問題)。事實上,目前幾乎唯一能夠為使用者空間鎖(如基於 futex 的 pthread 互斥鎖)實現良好確定性的技術就是優先順序繼承。

目前(沒有 PI),如果高優先順序和低優先順序任務共享一個鎖[這對於大多數非平凡的 RT 應用程式來說是一個非常常見的場景],即使所有臨界區都經過仔細編碼以確保確定性(即所有臨界區的持續時間都很短,並且只執行有限數量的指令),核心也無法保證高優先順序任務的任何確定性執行:任何中等優先順序的任務都可以在低優先順序任務持有共享鎖並執行臨界區時搶佔它,並且可以無限期地延遲它。

實現

如前所述,啟用 PI 的 pthread 互斥鎖的使用者空間快速路徑完全不涉及核心工作 - 它們的行為與普通基於 futex 的鎖非常相似:值 0 表示未鎖定,值 == TID 表示已鎖定。(這與基於列表的魯棒 futex 使用的方法相同。)使用者空間使用原子操作來鎖定/解鎖這些互斥鎖,而無需進入核心。

為了處理慢速路徑,我們添加了兩個新的 futex 操作

  • FUTEX_LOCK_PI

  • FUTEX_UNLOCK_PI

如果鎖獲取快速路徑失敗,[即從 0 到 TID 的原子轉換失敗],則呼叫 FUTEX_LOCK_PI。核心完成所有剩餘的工作:如果還沒有 futex 佇列附加到 futex 地址,那麼程式碼會查詢擁有 futex 的任務[它已將自己的 TID 放入 futex 值],並將一個“PI 狀態”結構附加到 futex 佇列。pi_state 包括一個 rt-mutex,它是一個支援 PI 的基於核心的同步物件。“另一個”任務成為 rt-mutex 的所有者,並且 FUTEX_WAITERS 位在 futex 值中以原子方式設定。然後,此任務嘗試鎖定 rt-mutex,並在此阻塞。一旦返回,它就獲得了互斥鎖,並將 futex 值設定為自己的 TID 並返回。使用者空間無需執行其他工作 - 它現在擁有鎖,並且 futex 值包含 FUTEX_WAITERS|TID。

如果解鎖端快速路徑成功,[即使用者空間設法對 futex 值進行 TID -> 0 原子轉換],則不會觸發任何核心工作。

如果解鎖快速路徑失敗(因為 FUTEX_WAITERS 位已設定),則呼叫 FUTEX_UNLOCK_PI,並且核心代表使用者空間解鎖 futex - 並且還會解鎖附加的 pi_state->rt_mutex,從而喚醒任何潛在的等待者。

請注意,在這種方法下,與以前的 PI-futex 方法相反,沒有 PI-futex 的先前“註冊”。[由於 pthread 互斥鎖的現有 ABI 屬性,無論如何這不太可能。]

此外,在這種方案下,“魯棒性”和“PI”是 futexes 的兩個正交屬性,並且所有四種組合都是可能的:futex、robust-futex、PI-futex、robust+PI-futex。

有關優先順序繼承的更多詳細資訊,請參見支援 PI 的 RT-mutex 子系統