RFC-0085:減少 zx_status_t 空格

RFC-0085:減少 zx_status_t 空間
狀態已接受
領域
  • 核心
  • 系統
說明

請減少有效 zx_status_t 值的範圍,讓類型更容易嵌入其他型別。

問題
毛皮變化
  • 436685
作者
審查人員
提交日期 (年-月-日)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] ( 是指 -10737418240)。屬於這個範圍的所有值都會 系統定義的錯誤代碼或單一成功代碼 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_NEXTZX_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