RFC-0240:物件上的非同步作業

RFC-0240:物件上的非同步作業
狀態已接受
區域
  • Kernel
說明

定義 Zircon 中的非同步作業如何與物件互動,以及如何處理作業。

Gerrit 變更
作者
審查人員
提交日期 (年-月-日)2024-02-06
審查日期 (年-月-日)2024-03-11

摘要

這項提案建議在 Zircon 核心中執行非同步作業時,應使用核心物件,且作業不應與用於註冊這些作業的控制代碼繫結。

提振精神

Zircon 會定義核心物件的非同步等待作業。我們想新增具有副作用的非同步作業,例如非同步管道讀取。為此,我們需要確定這些作業的語意,以及這些作業與所涉控制代碼和/或物件上其他作業的互動。

object_wait_async 是非同步作業的範例,會在物件狀態變更時產生埠封包。目前的 API 會嘗試分割基礎物件上執行的作業之間的差異 (如名稱所示),以及識別作業的控制代碼。

利害關係人

Zircon

協助人員:

由 FEC 指派,負責在 RFC 程序中引導此 RFC 的人員。

審查者:

  • maniscalco@google.com
  • cpu@google.com
  • abarth@google.com

已諮詢:

社交:

需求條件

定義非同步核心作業的關係,包括 object_wait_async,並處理轉移和關閉控制代碼等互動。

設計

總覽

Zircon 中的非同步作業會在物件上運作 (而非控制代碼)。物件狀態的變更可能會影響這些作業。用於參照物件的控制代碼變更不會影響非同步作業的行為,但以下特別說明的管道除外。註冊後,非同步作業會持續執行,直到完成、明確取消或關閉物件的所有控制代碼為止。系統會更新通訊埠上取消非同步作業的機制,以反映新的語意。

系統呼叫變更

object_wait_async

  • 從說明文件和支援程式碼中移除「如果控制代碼已關閉,與其相關聯的作業也會終止,但佇列中已有的封包不受影響。」這句話。

註冊後,非同步等待會持續有效,直到物件狀態變更為符合觀察到的條件、等待作業明確取消,或物件的所有控制代碼都已關閉為止。

port_cancel

  • 淘汰 port_cancel,並提供 port_cancel_key 做為替代方案,使用指定金鑰取消指定通訊埠上的所有作業。簽名:
zx_port_cancel_key(zx_handle_t port, uint32_t options, uint64_t key)

您也可以趁這個機會新增目前缺少 port_canceloptions 參數。

或者,您也可以更新 port_cancel 的實作方式,忽略 source 參數。在實務上,可取消的連接埠作業會以每個作業的專屬金鑰註冊。這個鍵通常是分配給處理作業本身的資料結構位址。有證據顯示這項變更很安全 (請參閱「回溯相容性」一節),但使用相同名稱時,要安全地部署這項變更並回收 options 片段會很困難。為作業使用新名稱,即可逐步更新程式碼,並追蹤舊作業的呼叫端。

object_wait_oneobject_wait_many 置換為 handle_close

  • 明確記錄的功能集沒有任何變更。在同步等待期間關閉控制代碼的文件已遭淘汰。

這些是針對控點所識別的一或多個物件進行的同步等待。我們目前的文件指出,關閉控制代碼會透過這些作業取消任何目前待處理的等待,但這本質上是競爭條件,因為關閉控制代碼的執行緒無法知道呼叫 object_wait_{one,many} 的另一個執行緒是否已解析該控制代碼。兩個程式彼此競爭,可能會觀察到 ZX_ERR_CANCELEDZX_ERR_BAD_HANDLEhandle_closeobject_wait_{one,many}我們可以提供無競爭條件的方式,透過將控制代碼與物件取消關聯 (https://fxrev.dev/949517),或讓程式更容易等待多個條件,以便在使用者空間中同步處理控制代碼的存取權,取消這些同步等待作業。由於目前尚不清楚作業中何時需要有效的控制代碼,因此這項提案不會變更行為。

channel_callchannel_call_etc

  • 明確記錄的功能集沒有任何變更。

目前這些函式具有隱含說明文件,說明與 ZX_ERR_CANCELED 傳回值中 object_wait_{one,many} 相同的取消行為。一般情況下,使用 handle_cancel 時,這些作業也會發生相同的競爭條件問題,但由於這項作業會公開更多內部詳細資料,因此在實際情況中,可能會出現不會發生競爭條件的情況。呼叫端無法在逾時以外的範圍,將 channel_call 的內部等待時間設為參數,因此程式無法使用多個條件來協調關機。如要提供無爭議的取消作業,我們需要定義獨立的作業,例如 https://fxrev.dev/949517 中建議的作業。與 object_wait_{one,many} 相同,雖然目前的行為可疑,但這項 RFC 並未提議對這些作業的行為進行任何變更。

頻道排序

通道在 Fuchsia 系統架構中扮演獨特角色,目前核心中具有特殊案例邏輯,可驗證管道上的作業是否只在控制代碼由呼叫程序擁有時成功處理。系統會廣泛使用管道來交換資料和功能。這些檢查的目的是在不同信任層級運作的程序之間傳遞控制代碼時,維護管道的機密性和完整性。程序取得管道控制代碼後,就能保證擁有該端點的專屬存取權,可讀取及寫入訊息。如要保留這個屬性,並採用 RFC 中建議的語意,同時允許日後的非同步管道作業,我們可以利用通道的另一個屬性,也就是管道端點只有一個控制代碼。對管道控制代碼執行的移轉作業可視為對物件本身的作業,我們可能會導致管道上待處理的變異作業,或移轉嘗試失敗。

觀察物件狀態 (例如 READABLE 和 WRITABLE 信號) 不會違反我們重視的屬性。如果程式可以觀察管道何時可讀取或寫入,即使轉移這個控制代碼也沒關係,因為這項資訊不會攜帶功能,也不會攜帶系統狀態的重要機密資訊。也就是說,對於有這項提案的管道,object_wait_async 作業不需要有不同的行為。日後對管道執行的作業 (例如非同步讀取) 必須考量與轉移作業的互動。

實作

這項變更對使用者空間的主要實際影響,是取消通訊埠物件上的非同步物件等待。非同步調度器程式庫需要為可取消的作業分配及追蹤專屬鍵 (這類程式庫已具備這項功能),如果沒有使用物件,就不再需要追蹤控制代碼值。系統會將對 port_cancel 的呼叫機械式翻譯為 port_cancel_key,方法是將第二個參數從控制代碼值變更為字面值 0

在核心端,觀察器、埠和物件表示法之間的關係非常細微。這項變更會移除取消程序期間的控制代碼資料表鎖定依附元件,並啟用控制代碼管理邏輯的未來重構,藉此簡化部分複雜性。短期內,如要實作這項變更,最簡單的方法是使用空值 Handle 註冊非同步等待,並在觀察器觸發時,將註冊的等待標示為已取消,然後清除觀察器狀態,藉此執行非同步等待取消作業。

效能

這項變更可減少非同步作業的 Kernel 簿記量,以及控制代碼資料表鎖定的壓力,在特定類型的負載下可能會有幫助。目前的微型基準測試顯示,簡單的原型實作方式不會造成重大變化。使用者空間程式庫也可以儲存較少的資訊,以便取消已註冊的非同步作業。

人體工學

如要取消個別非同步作業,應用程式必須追蹤鍵值。在實際的調度器實作項目中,這項作業已完成 (除了保留控制代碼值之外)。

回溯相容性

這會以細微的方式變更 object_wait_asyncport_cancel 的記錄和實際語意。這項異動不會影響維持下列屬性的計畫:

  • 系統會為每個非同步等待作業註冊專屬鍵
  • 等待中的物件控制代碼未關閉或轉移,且註冊的等待作業仍待處理

這些說法在今天大致上仍適用。非同步等待通常與狀態分配相關聯,用於處理等待結果,而這些等待的 key 通常是根據此分配的位址計算,該位址在位址空間中或在其他形式的專屬 ID 上必須是專屬的。控制代碼通常會儲存在擁有資料結構中,關閉控制代碼需要經過某種關機程序,清除對控制代碼的參照。

https://fxrev.dev/984701 是會忽略 source 參數的 port_cancel 原型。有一個 Zircon 核心測試會刻意重複使用金鑰,樹狀結構中的所有其他測試案例都會未經修改而通過。這表示 port_cancel 的變更與目前的程式碼相容。

https://fxrev.dev/986494 是相關原型,可將已註冊控制代碼的生命週期與觀察器分離。這會評估我們是否依賴關閉控制代碼來取消未完成的非同步等待作業。所有現有測試都通過未修改的這項變更,表示這項行為變更與目前的程式碼相容。

安全性考量

這項提案允許程序在某些情況下,觀察不再有控制代碼的物件狀態變化。在這個模型中,控制代碼代表啟動非同步作業的能力。一般而言,我們不會保證控制代碼代表對物件的專屬存取權,但具有不可重複控制代碼的物件 (最明顯的是管道) 除外。

對於大多數授予可重複控制代碼的物件類型,擁有控制代碼的程序無法推斷該控制代碼上存在哪些其他控制代碼和作業,除非該程序瞭解該控制代碼的完整歷程記錄 (包括建立或從信任來源轉移)。如果允許非同步作業在控制代碼轉移後持續存在於物件上,這項分析不會有顯著變化,因為登錄機構同樣可以輕鬆保留重複的控制代碼。

就頻道而言,我們一律授予不重複的帳號代碼,因此保證管道擁有帳號代碼的專屬存取權。允許管道代碼的前任擁有者查看管道在轉移後首次可讀取的時間,可能不會造成安全疑慮。導入與透過管道傳送的訊息內容互動的作業時,我們需要謹慎處理,確保只有目前的帳號代碼擁有者才能執行這些作業。

測試

通訊埠和非同步物件行為的變更,將透過 Zircon 的核心測試套件進行測試。我們會檢查程式庫及其測試套件,評估程式庫的相容性,特別是分派器程式庫。現有的整合套件會通過新行為的原型 (請參閱「回溯相容性」一節),我們可以在將變更部署至 object_wait_async 時密切監控這些套件。

說明文件

您需要為新的 port_cancel_key 新增系統呼叫說明文件,並根據設計章節的說明,更新現有作業的說明文件。

缺點、替代方案和未知事項

以控制代碼為基礎的替代語意

其中一個替代方案是繼續將非同步作業繫結至其啟動控制代碼 (如部分現有文件所述),並在新增非同步作業時維持這項關係。這會增加這些新作業的複雜度,並讓重構和最佳化核心的控制代碼管理邏輯更加困難,同時對應用程式邏輯的實用性影響不大。

port_cancel重複使用

我們不必定義新的 port_cancel_key 系統呼叫,而是可以將現有 port_cancel 上的 source 參數替換成大小相同的 options 參數。在過渡期間,這個欄位不支援任何選項,但允許使用控制代碼值。在這段轉換期間,我們會找出並更新所有 port_cancel 的呼叫端,以便在這個欄位中傳遞 0 值,而不是目前提供的控制代碼值。過渡期結束後,我們會開始強制將該欄位設為零,屆時即可開始導入選項值。這種做法的缺點是,可能難以偵測所有呼叫端何時更新為新語意。在實務上,很少會在觸發非同步等待前取消,因此 port_cancel 的動態分析可能找不到只在異常錯誤處理或時間情況下觸發的呼叫端。

既有技術和參考資料

Zircon 控點解析模型 - 2020 年的 RFC 草案,探討了其中一些問題。

zx_handle_cancel - 草案 RFC,定義在控制代碼上取消同步作業的機制,避免控制代碼解析競爭。

async-loop key management

zxwait key management

Fuchsia 非同步金鑰管理