NAME
futex - 建立使用者空間同步處理工具的基礎。
概要
futex 是快速使用者空間的 muTEX。這是低階同步基本功能,是較高層級 API (例如 pthread_mutex_t
和 pthread_cond_t
) 的建構模塊。
Futexes 的設計目的是不進入核心,或在未經競爭的情況中分配核心資源。
說明
Zircon futex 實作目前支援透過超過 6 個系統呼叫分散的三種作業:
zx_status_t zx_futex_wait(const zx_futex_t* value_ptr,
zx_futex_t current_value,
zx_handle_t new_futex_owner,
zx_time_t deadline);
zx_status_t zx_futex_wake(const zx_futex_t* value_ptr, uint32_t wake_count);
zx_status_t zx_futex_wake_single_owner(const zx_futex_t* value_ptr);
zx_status_t zx_futex_requeue(const zx_futex_t* value_ptr,
uint32_t wake_count,
zx_futex_t current_value,
const zx_futex_t* requeue_ptr,
uint32_t requeue_count,
zx_handle_t new_requeue_owner);
zx_status_t zx_futex_requeue_single_owner(const zx_futex_t* value_ptr,
zx_futex_t current_value,
const zx_futex_t* requeue_ptr,
uint32_t requeue_count,
zx_handle_t new_requeue_owner);
zx_status_t zx_futex_get_owner(const zx_futex_t* value_ptr, uint64_t* koid);
以上所有項目都會共用 value_ptr
參數,也就是對齊的使用者空間整數的虛擬地址。這個虛擬位址是核心使用的資訊,用於追蹤特定執行緒等待中的項目。核心目前不會修改 *value_ptr
的值 (但會有日後可能執行的作業,請見下文)。至於使用者空間程式碼,必須正確地修改所有執行緒中的這個值,以建構互斥鎖等。
請注意,使用地址標記時,使用者空間指標不一定能同時與核心中的 futex 執行個體進行一對一對應。已移除架構專屬標記資訊的位址,會用於日後 ID。例如,在 ARM 中,如果已啟用 Top-Byte-Ignore (TBI),具有 0x0A000000FF123450
值的 futex 指標與值為 0x0B000000FF123450
的 futex 指標相同,因為儘管標記 (0x0A
和 0x0B
) 不同,其地址位元相同。
詳情請參閱 zx_futex_wait()
、zx_futex_wake()
、zx_futex_requeue()
和 zx_futex_get_owner()
手冊頁面。
權利
Futex 物件沒有任何相關聯的權利。
使用者空間程式碼只能執行 2 種原始作業:等待和喚醒 (重新排入佇列是這兩者的組合)。由於未來程序僅是程序本機概念,撤銷任一項作業的存取權會導致日後功能毫無意義。
此外,從核心的角度來看,futexe 是暫時物件,狀態只會在 futex 有等候程序的情況下存在。如果核心中沒有更耐用的狀態,則更或更不可能針對未來性權利的持續概念。
與 Linux futexe 的差異
請注意,使用者空間指標虛擬位址中的所有 Zircon futex 作業金鑰。這與 Linux 實作不同,後者用於區分私人未來的作業 (對應至僅限程序中的運算),以及跨位址空間共用的。
如上所述,所有 futex 運算都會留下未透過核心修改的 Futex 值。其他可能的作業 (例如 Linux 的 FUTEX_WAKE_OP
) 需要從核心中進行整體化的值,目前的實作並不需要。
擁有權和優先順序繼承
總覽
部分執行階段可能需要根據 futexe 的元件實作同步處理基本功能,這些基元表示優先繼承行為。為支援這些使用者,zircon futexes 有個「擁有權」概念,可用於實作這類原始物件。您可以選擇是否要使用這項功能。
未來任何時候,未來利潤可能是無人擁有,或由單一執行緒擁有。當執行緒擁有一或多個 futexe 時,有效優先順序會成為其基本優先順序的最大值,同時也是目前所有 futexe 目前等候者的優先順序。一旦一個執行緒不再擁有未來存在,那麼豆腐服務等候人員的壓力就會從上述關係中消失。一旦執行緒不再擁有任何舊項目,其優先順序就會放寬至基本優先順序。
模糊化擁有者信號負責使用者空間程式碼,正如建構需要優先繼承行為的特定同步物件時,要妥善套用擁有權概念。
Zircon futexe 最多只能有一位擁有者。不支援為了優先順序繼承的目的而針對 futexe 的多個擁有權。而且,同一名之前牛仔褲的主人永遠不能同時是同一人。
指派擁有權
系統會透過每項「等待」或「重新排入佇列」作業,指派 futex 擁有權。如果是重新佇列作業,目標 futex 是重新佇列 futex,而非 wake_futex。使用者會將控制代碼傳遞至執行緒,指出該執行緒目前的擁有者應由誰負責,如果不應的擁有者,則為 ZX_HANDLE_INVALID。
- 將有效的控制代碼傳遞至執行緒,表示該未來擁有者是使用者空間程式碼的責任。如果傳遞無效的控制代碼,或傳送至非執行緒物件的控制代碼,會導致等候/重新佇列作業失敗。
- 尚未啟動的執行緒可能無法擁有未來性。只要嘗試將 futex 的擁有權指派給尚未啟動的執行緒,就會導致等待/重新排入佇列作業失敗。
- 退出的討論串可能不是未來生活的擁有者。如果執行緒在擁有 futex 時結束,則系統會重設為無人擁有該執行緒。如果使用者嘗試將 futex 的擁有權指派給已經結束的執行緒,等待/重新佇列作業的行為會像是傳遞 ZX_HANDLE_INVALID 做為新 futex 擁有者的情況。
- 如果等候/重新佇列作業成功,目標 futex 的擁有者「一律」會設為指定的執行緒;如果傳遞 ZX_HANDLE_INVALID,則不予設定。
- 具體而言,如果因為預期的 futex 值與實際 futex 值不符,導致等候/重新佇列作業失敗,futex 的擁有者將維持不變,而作業的狀態碼將是 ZX_ERR_BAD_STATE。無論傳遞的值是否為代表擁有權的控制代碼,系統都會傳回此錯誤代碼,即使傳遞的值導致傳回 ZX_ERR_BAD_HANDLE 的狀態也是如此。
轉移擁有權
在 Wake 作業或重新佇列作業期間,核心可代表使用者轉移 Cutex 的擁有權。如果是重新佇列作業,移轉作業的目標為 Wake_futex,而非 requeue_futex。只有在使用 Wake/重新佇列作業的 zx_futex_wake_single_owner()
或 zx_futex_requeue_single_owner()
變化版本時,系統才會執行擁有權轉移作業。這些作業的 single_owner
變體只會釋出一個等候程序,並將該錯誤的擁有權指派給已發布的執行緒。
- 如果喚醒作業期間「沒有」等候程序,則目前沒有擁有者。這項異動將保持不變。
- 如果重新佇列作業因為預期的 futex 值與實際未來值不相符而失敗,該函式的擁有者將維持不變。
- 如果喚醒/重新佇列作業的非單獨擁有者變化版本呼叫,會導致目標 futex 的擁有者設定為無任何項目。
有關牛仔的紙
Fuss、Futexes 和 Furwocks:在 Linux 中快速鎖定使用者、Hubertus Franke 和 Rusty Russell
這是說明 Linux futex 的原始白皮書。這項工具記錄了原始實作的記錄和設計,先前 (失敗) 嘗試建立快速的使用者空間同步處理原始物件,以及效能測量。
Futexes Are Tricky、Ulrich Drepper
本文件說明 Linux 中可能存在的一些問題和實作詳細資料。本文會討論核心實作,並進一步說明互斥鎖、條件變數等正確且有效率的使用者空間實作方式。
-
針對「Futexes 很有棘手」的論述,簡要說明一個簡單的實作方式,可避免使用
FUTEX_CMP_REQUEUE
鎖定 WebKit、Filip Pizlo
深入瞭解在 WebKit 中鎖定原始物件,並取得基準和分析的說明。包含「停車空間」概念的詳細說明,可讓您以非常精簡的方式呈現使用者空間互斥鎖。