RFC-0085:減少 zx_status_t 空間 | |
---|---|
狀態 | 已接受 |
領域 |
|
說明 | 請減少有效 zx_status_t 值的範圍,讓類型更容易嵌入其他型別。 |
問題 | |
毛皮變化 | |
作者 | |
審查人員 | |
提交日期 (年-月-日) | 2020-10-09 |
審查日期 (年-月-日) | 2021-04-08 |
摘要
本文件建議減少有效 zx_status_t
值的範圍
從所有 32 位元帶正負號整數到較小的 [-2^30, 0]
範圍內,以及
淘汰應用程式定義的錯誤代碼。這樣一來,
zx_status_t
,可輕鬆嵌入其他型別的子範圍。
提振精神
zx_status_t
是一種簡單的錯誤類型,用來指出
表示特定動作成功與否定義是
帶正負號 32 位元整數。值 ZX_OK
(0) 表示作業
成功。所有其他值都代表某表單有錯誤
其中含有系統定義的錯誤代碼 (負值) 和
系統支援應用程式定義的錯誤代碼 (正值)。
zx_status_t
類型廣泛用於 Fuchsia。例如:
同時用於 Zircon 核心 (包括內部以及
Ssyscalls 的值);用於許多 FIDL 通訊協定來表示錯誤;
用於回報錯誤;且經常使用
實作在純應用程式的程式碼中
回報函式之間的錯誤。
儘管 zx_status_t
目前的定義允許各種不同的
錯誤狀況,因此目前只有
就是能達成一個成功價值Fuchsia 開發人員長期變化
發現一些應用實例
有助於達成這個目標
將其他非錯誤訊息資訊傳達給呼叫端:
非錯誤警告:有些函式會發出警告,而 這個函式大致上成功,但有潛在問題。適用對象 例如成功寫入緩衝區的要求,但緩衝區 少於可用的資料量
有關物件狀態的其他資訊: 舉例來說,核心處理序間通訊 (IPC) 基元可能希望 能指出更多 狀態顯示為待處理狀態 以便瞭解通訊端等類型的門檻資訊
流量控制:核心和系統程式庫中的常見模式 是供回呼傳回錯誤,值
ZX_ERR_STOP
至 表示不應再呼叫回呼,或設為ZX_ERR_NEXT
, 表示應繼續呼叫回呼。這些 值 (但「每」沒有錯誤) 目前已指派 代碼。通訊小型酬載:函式可能會想要 並在結果中表示 呼叫成功。舉例來說,目前的
zx_debuglog_read
syscall 恰好運用的正值zx_status_t
:傳回在緩衝區中讀取的位元組數量 成效。
理論上所有這些應用情境,理論上都能使用 例如其他參數或較複雜的化合物型別 注重效能的用途時,如果函式 可能會有簡單的整數/註冊回傳值,能夠處理 用途
本文件中,會用到「函式」和「傳回代碼」相關詞彙。 這些概念也適用於 FIDL 呼叫、Syscalls 等同樣地 這個設計雖然在 C++ 中提供範例,同樣的概念也適用於 包括 C、Rust 和 Go
設計
在本提案中,zx_status_t
仍然是帶正負號 32 位元整數。
會繼續定義為只有單一成功代碼 ZX_OK
(0)。
所有其他值仍應視為錯誤。
不過,我們會更新 zx_status_t
的定義,以便:
有效
zx_status_t
值的範圍為[-2^30, 0]
( 是指-1073741824
至0
)。屬於這個範圍的所有值都會 系統定義的錯誤代碼或單一成功代碼ZX_OK
。應用程式定義的錯誤代碼 (目前定義為所有陽性)
zx_status_t
值) 已淘汰,如下所述 「回溯相容性」。
只要限制 zx_status_t
可採用的值範圍,使用者就能
沒有將 zx_status_t
值的範圍嵌入另一種類型,
錯誤代碼值會與非錯誤傳回值重疊。適用對象
舉例來說,函式可能會定義 result_or_count_t
類型,其中負數為負值
值會對應至 zx_status_t
錯誤代碼,
非負值則會對應到已處理的元素數量。
我們要求函式實作者定義新類型,不僅僅是
會在 zx_status_t
空間未使用的部分發出值。這可以確保
函式的使用者將清楚瞭解函式傳回的內容,
如果函式擁有傳回類型,則應該解譯為
zx_status_t
,使用者保證 ZX_OK
是唯一有效的
。
範例
以下章節將會展示上述各種用途如何
系統會假設有限範圍的 zx_status_t
來處理。
其他狀態資訊
目前,zx_channel_read
的使用者只能決定
出現訊息等待管道讀取失敗而等待。使用此應用程式
zx_channel_read
提案可能會引入新的傳回類型
可提供「更多訊息正在等待」做為傳回值的一部分
避免產生額外的系統呼叫:
/// Keep reading messages until none remain on the channel.
do {
// Read from the channel.
zx_channel_read_result_t result =
zx_channel_read(channel, buffer, /*options=*/ZX_GET_CHANNEL_STATE);
// `zx_channel_read_result_t` defines negative values to correspond
// to `zx_status_t` error codes.
if (result < 0) {
return static_cast<zx_status_t>(result);
}
// Otherwise, the result is defined to be a bitmap indicating
// the state of the channel.
} while ((result & ZX_CHANNEL_MORE_MESSAGES_WAITING) != 0);
流量控制
與其依賴錯誤代碼 ZX_ERR_NEXT
和 ZX_ERR_STOP
(並仰賴說明文件向呼叫端說明需要哪些代碼
就會導入新的型別,這個型別會使用非負數空間
用於表示流量控制:
// Negative values are zx_status_t error codes, while non-negative
// values must be one of the constants below.
using zx_iteration_status_t = int32_t;
constexpr int32_t ZX_ITERATION_CONTINUE = 0;
constexpr int32_t ZX_ITERATION_DONE = 1;
// ...
while (true) {
zx_iteration_status_t result = Next(thing);
if (result < 0) {
return result; // error
}
if (result == ZX_ITERATION_DONE) {
break;
}
// ...
}
在回應中混合酬載
zx_debuglog_read
已使用非負數來傳回
酬載 (讀取的位元組數),目前違反
「zx_status_t
」的定義這項提案能夠
zx_debuglog_read
可定義新類型,以明確表示傳回方式
應解讀為:
// Read the debug log. Returns a negative value on error, otherwise
// the number of bytes read from the debug log.
zx_debuglog_read_result_t result = zx_debuglog_read(buffer);
if (result < 0) {
return result; // error
}
print_log(/*buffer=*/buffer, /*size=*/result);
應用程式定義的錯誤代碼
如要自行定義錯誤代碼的應用程式 但應定義型別,清楚說明值 解譯:
enum ApplicationError {
INVALID_AUTHORIZATION = 1,
TOO_MANY_OUTSTANDING_REQUESTS = 2,
// ...
}
// Zero indicates success. Negative values map to `zx_status_t` error
// codes. Positive values map to `ApplicationError` error codes.
using app_status_t = int32_t;
由於 zx_status_t
只會佔用 [-2^30, 0]
的範圍,因此應用程式
可以使用 [-2^31, -2^30)
範圍
應用程式定義的錯誤代碼,因此請將
儲存其他傳回碼的空間
回溯相容性
本提案會將 zx_status_t
的有效範圍更新為值
[-2^30, 0]
,所有這些都是系統定義。不過
目前有一小群應用程式
應用程式的專用程式碼
進行此 RFC 實作時,我們將遷移
變更為新 (非 zx_status_t
) 類型的正狀態碼。
實作
實作此 RFC 的必要步驟如下:
更新描述文件內容的說明文件 (包括 Markdown 文件和來源註解) 語意
zx_status_t
,以符合本規格提議的用途。更新
zx_debuglog_read
syscall 以使用自訂 (非zx_status_t
) 類型。更新
zx_status_t
正面狀態範圍的現有使用者,以便使用 這種新型別可更準確地說明系統產生的其他錯誤。
成效
首先是這種編碼配置的效能機制 se。大多數情況下,成效變化應不大 與其他方式的編碼方式相比。適用對象 同時具有高成本或稀少參數 也許能稍微改善成效
第二是系統 API 的效能變化 改為使用 並提供更豐富的資訊其中一項便是動力 就是向使用者空間傳達更多資訊 做出更明智的決策,進而提升成效
整體而言,我們預期應用程式能力 用來傳達額外資訊的系統呼叫 會稍微複雜的程式碼來評估狀態值
除了成效、這項變更和日後的變更 能力可能會變更多個二進位檔的程式碼大小,尤其是 所產生的 FIDL 繫結
安全性考量
將 zx_status_t
範圍嵌入其他類型可能會有
可能會造成混淆,也因此可能會引發軟體錯誤。函式或
執行這類嵌入的通訊協定應謹慎評估
但風險遠大於混淆風險
遷移函式時,使用 zx_status_t
和
發出更明確的應用程式專屬錯誤代碼
減少混淆的可能性
隱私權注意事項
本提案不會以有意義的方式與使用者資料互動, 這不會影響隱私權
測試
系統會根據上述幾個新功能開發單元測試。
說明文件
在樹狀結構中,Markdown 說明文件和程式碼中註解將更新為
反映 zx_status_t
的新定義。
缺點、替代方案和未知
缺點:來自不受信任來源和 FIDL 繫結的 zx_status_t
值
目前無法防止超出範圍的 zx_status_t
值
多半透過管道傳輸資料收到 zx_status_t
值的應用程式
並要求這些來源位於不受信任的來源,必須手動
進行驗證長期而言,您可能需要更新 FIDL 繫結
產生器,檢查並拒絕超出範圍的 zx_status_t
值,
這個架構與 RFC 無關。
替代做法:核心退出參數
為核心的另一個設計空間 引數。這種做法有一些缺點:
變更這些系統呼叫的類型更具侵略性 並需要較長的遷移時間
所有系統呼叫都必須使用具有 或呼叫端對額外資訊不感興趣 然後傳入空值。兩者都是根據人體工學降級,
使用外引數來傳達少量資訊
浪費資源使用稀少和昂貴的資源
使用其中一個暫存器 (尤其是 x86_64),或
透過指標可相當昂貴 user_copy
替代做法:保留 zx_status_t
的非負值以免費使用
此提案提議限制有效 zx_status_t
值的範圍
協助將範圍嵌入其他類型,但不允許
直接使用未使用的範圍
先前的提案會分割 zx_status_t
空間並預留負值
,並允許函式視需要使用非負值。
如果允許基於特定函式用途重複使用 zx_status_t
類型,
方便開發人員傳回額外資源
函式中的酬載 (無需建立額外類型),
事實證明,讓核心系統呼叫能開始傳回額外的
資料傳送至特定呼叫端,而不會中斷現有呼叫端的 ABI。
但缺點是,無法確定值的範圍為何 函式可能會單看其類型而傳回。此外,廣泛應用於 慣用語,例如:
zx_status status = CallFunction();
if (status != ZX_OK) {
return status;
}
如果 CallFunction
使用正數,則不保證正確無誤
傳回值。
zx_status_t
導致我們拒絕受理。
替代做法:將分區為錯誤和成功代碼
先前的提案已建議將zx_status_t
劃分為
各組錯誤代碼和成功代碼的範圍
再細分為系統定義和應用程式定義的範圍
這種拆分方式有幾個缺點:
系統定義的「成功」代碼的效用並不明確: 雖然錯誤代碼經常會向上傳播至呼叫堆疊 通常會立即處理或直接捨棄。 不必仰賴全球通用的成功代碼組合 語意
將正值限制為只使用成功代碼可避免其他 更有效率地使用值,例如傳回位元欄位 物件目前狀態的資訊,或傳回小型酬載 例如位元組數
需要遷移成功代碼才能重新運用正向空間 目前用於特定應用程式的程式碼 錯誤代碼。
允許個別使用者使用整個非負數空間 函式可以減輕遷移負擔,並為開發人員提供更多 靈活彈性
既有藝術品和參考資料
Linux kernel 內部會使用負數範圍來發生錯誤, 將正範圍保留用於特定函式的用途。大多數 syscalls 將此單一值分割為傳回代碼和執行緒本機
errno
變數位於 syscall 邊界。UEFI 規格會將狀態空間分割為負值 (錯誤)、零 (成功) 和正值 (警告)。兩者 錯誤和警告範圍會進一步分成「EFI 保留」 範圍和 OEM 範圍,盡可能使用第二重要的位元。
版本記錄
2021-03-12:移除提案的一部分建議新錯誤 程式碼,指出已收到超出範圍的
zx_status_t
值。 系統會改為稽核樹狀結構內程式碼,以移除這類用法和 FIDL 繫結 產生器會更新,避免超出範圍值 跨越程序界限。2021-03-09:修改提案,重新定義 有效的
zx_status_t
值必須設為[-2^30, 0]
。縮減範圍zx_status_t
,更容易嵌入其他類型的子範圍。2021 年 2 月 10 日:修改提案,拆分為負值 應用程式錯誤和系統錯誤之間
zx_status_t
,但 確保應用程式可用的所有非負數值 以便提供更準確的解釋2020-10-09:拆分
zx_status_t
錯誤的初始提案 分為四個分區:應用程式錯誤和系統錯誤 負值;而系統成功代碼和應用程式成功時 代碼會是正值0 仍是ZX_OK
。