RFC-0010:zx_channel_write 和 zx_channel_call 支援 zx_channel_iovec_t | |
---|---|
狀態 | 已接受 |
領域 |
|
說明 | 這個 RFC 針對 zx_channel_write 和 zx_channel_call 導入一個新模式,會從多個記憶體區域複製輸入資料,而非從單一連續緩衝區中複製輸入資料。 |
問題 | |
毛皮變化 | |
作者 | |
審查人員 | |
提交日期 (年-月-日) | 2020-09-25 |
審查日期 (年-月-日) | 2020-10-06 |
摘要
這個 RFC 為 zx_channel_write
、zx_channel_write_etc
、
複製輸入資料的來源 zx_channel_call
和 zx_channel_call_etc
多個記憶體區域,而不是單一連續緩衝區。這個
允許簡訊資料
直接從多個 userspace 物件複製而來
包括處理、複製和版面配置步驟方法是更新現有的
系統呼叫以擷取 zx_channel_iovec_t
記憶體區域描述元陣列
當已指定選項時
提振精神
這個提案的主要動機是成效。
如為非線性化的網域物件,目前必須 (1) 分配 FIDL 繫結
緩衝區,以及 (2) 在標準版面配置中將物件複製到緩衝區中。之後
就會再次將緩衝區複製到核心中zx_channel_iovec_t
允許
以便直接將物件複製到核心中以及 FIDL 訊息
資料再按照標準順序排列,只有
zx_channel_iovec_t
陣列必須反映所需順序。
設計
zx_channel_write 目前的簽名如下:
zx_status_t zx_channel_write(zx_handle_t handle,
uint32_t options,
const void* bytes,
uint32_t num_bytes,
const zx_handle_t* handles,
uint32_t num_handles);
輸入資料是 bytes
指向的連續位元組陣列。
zx_channel_write_etc
、zx_channel_call
和zx_channel_call_etc
後來
都是類似陣列事實上,這些陣列必須是連續的
同時免除不必要的負擔特別是針對含有外部元件的 FIDL 訊息,
FIDL 編碼器必須分配一個緩衝區,並將資料移到合適的位置
。
zx_channel_iovec_t
提供替代路徑。zx_channel_write
,
zx_channel_write_etc
、zx_channel_call
和zx_channel_call_etc
而是接收物件的位置和大小清單
複製作業會在核心內進行,避免發生額外的重複情形,
分配速度。
在 C++ 中定義 zx_channel_iovec_t
如下:
typedef struct zx_channel_iovec {
void* buffer; // User-space bytes.
uint32_t capacity; // Number of bytes.
uint32_t reserved; // Reserved.
} zx_channel_iovec_t;
每個 zx_channel_iovec_t
都會指向接下來要複製的 capacity
個位元組
buffer
傳送至核心訊息緩衝區。「reserved
」必須指派給零。
只有在 capacity
為 0 時,buffer
欄位才會是空值。buffer
分
不能在多個 zx_channel_iovec_t
中重複
zx_channel_write
、zx_channel_write_etc
、zx_channel_call
的簽名
或 zx_channel_call_etc
維持不變。不過,如果使用者指定
設為這些系統呼叫的 ZX_CHANNEL_WRITE_USE_IOVEC
選項,void* bytes
引數會被解譯為 zx_channel_iovec_t*
。同樣地,
系統會將 num_bytes
引數解讀為 zx_channel_iovec_t
的數目
。
請注意,處理常式陣列的類型 (zx_handle_t
或
zx_handle_disposition_t
) 不相關,因為只有 bytes
陣列是
已變更。
zx_channel_iovec_t
陣列描述的訊息,且要傳送
否則無法在
全部。呼叫端無法再使用提供給 syscall 的帳號
也會對失敗和失敗情形發出請求
錯誤狀況
這些是 zx_channel_write
、zx_channel_write_etc
、
zx_channel_call
和 zx_channel_call_etc
含有更新檔,因為
以及 Ivecs 介紹
ZX_ERR_OUT_OF_RANGE num_bytes
或 num_handles
大於
ZX_CHANNEL_MAX_MSG_BYTES
或 ZX_CHANNEL_MAX_MSG_HANDLES
。
如果已指定 ZX_CHANNEL_WRITE_USE_IOVEC
選項,
如果 num_bytes
大於,就會產生 ZX_ERR_OUT_OF_RANGE
ZX_CHANNEL_MAX_MSG_IOVEC
或生物容量的總和超過
ZX_CHANNEL_MAX_MSG_BYTES
。
ZX_ERR_INVALID_ARGS bytes
是無效的指標,handles
是無效的指標,或 options
包含無效的選項位元。
如果已指定 ZX_CHANNEL_WRITE_USE_IOVEC
選項,
如果 buffer
欄位包含無效的指標,則為 ZX_ERR_INVALID_ARGS。
對齊
指定的位元組沒有對齊限制
zx_channel_iovec_t
。每個 zx_channel_iovec_t
都會在沒有邊框間距的情況下複製。
限制
現有限制的位元組數 (65536
) 和帳號代碼 (64
)
則訊息未變更請注意,這些限制適用於郵件,而非
zx_channel_iovec_t
個項目。
zx_channel_iovec_t
數量將限制為每個系統呼叫 8192
。這個
數字來自對齊的 8 位元組內嵌 + 行中物件數
可容納 65536
位元組訊息,且每個內嵌 + 行出物件
可能使用了 zx_channel_iovec_t
項目。
實作
Syscall
- 加入設計一節中定義的
zx_channel_iovec_t
類型。 - 新增「
ZX_CHANNEL_WRITE_USE_IOVEC
」 - 顯示的 syscall 介面沒有變更 (
zx_channel_iovec_t
陣列) 會傳入現有的bytes
參數。
核心
收到 ZX_CHANNEL_WRITE_USE_IOVEC
選項後,核心將:
- 將
zx_channel_iovec_t
物件指向的資料複製到訊息 緩衝區。雖然複製作業通常會依序執行zx_channel_iovec_t
輸入的值,請自行選用。不過, 訊息必須按照zx_channel_iovec_t
項目的順序排列。 - 將訊息寫入該管道。
FIDL
這是針對執行系統呼叫的系統呼叫變更提案 發生在核心內,且 FIDL 繫結變更的細節 超出範圍不過,為了方便評估這個提案 請務必瞭解這對 FIDL 編碼的影響。
FIDL 繫結可選擇使用 zx_channel_iovec_t
支援,
新增對將 FIDL 物件編碼至 zx_channel_iovec_t
陣列的支援功能。
這個編碼路徑和現有的編碼路徑
zx_channel_iovec_t
可讓核心就地複製物件。主要
小工具就是使用指標採用 FIDL 編碼的訊息需要
已傳送至核心,並以 PRESENT
或 ABSENT
標記取代指標
輕鬆分配獎金但在許多情況下,物件仍需要
系統呼叫後的原始指標值,讓解構函式
物件。
這表示使用 zx_channel_iovec_t
的繫結會
有時候需要多做筆記,確保在物件內
正確清理資料
遷移
由於此功能採用的是預設停用選項,因此 並不會立即影響到現有使用者。來電網站可遷移至 請視需要使用這個選項
實際上,我們的目標是遷移可因應
享有 zx_channel_iovec_t
的好處。這個數量應會減少
這對 FIDL 使用者的影響
成效
實作原型並已完成基準測試。
這個原型在核心端導入了 zx_channel_write 選項
和有限的 FIDL 支援 (僅限內嵌物件和向量)。
郵件標頭,以及每個內嵌和離線物件
有 zx_channel_iovec_t
個項目。
使用包含 64 個項目的陣列,將 zx_channel_iovec_t
儲存在
核心和 FIDL 編碼
這些測量數據來自使用 Intel Core i5-7300U CPU (2.60GHz) 的機器。
位元組向量事件基準 (zx_channel_write、zx_channel_wait_async 和 zx_channel_read) 的轉換率有顯著的成長:
- 4096 位元組向量:9398 ns ->4,495 奈秒
- 256 位元組向量:8788 ns ->3794 奈秒
FIDL 編碼也展現了效能改善。
將位元組向量範例的時間編碼:
- 4096 位元組向量:345 ns ->88 奈秒
- 256 位元組向量:251 ns ->86 奈秒
Inline 物件也會顯示少量編碼的改善:
- 有 256 uint8 欄位的結構:67 ns ->49 奈秒
安全性考量
由於這是現有系統呼叫的重大變更, 導入作業前必須先接受安全性審查。
隱私權注意事項
這不會對隱私權造成任何影響。
測試
每個變更圖層都會新增單元和整合測試。
但不打算加入裝置或系統層級的端對端測試,但 現有的測試涵蓋範圍有助於確保不會發生未預期的錯誤 以及遷移作業的間隔後
說明文件
系統呼叫說明文件需要更新,表示支援這項功能 而不是每個特徵的分數
無需變更整個架構的說明文件。
缺點、替代方案和未知
此提案的主要缺點是需要支援而變得更加複雜
核心中的選項,以及 FIDL 繫結的實際較為複雜性
使用 ZX_CHANNEL_WRITE_USE_IOVEC
選項,需要確保
如果物件經過變更,方便就位複製完成,就會正確清理。
限制
引數的 zx_channel_iovec_t
數量下限有上限
比 8192
更接近 16
。這樣一來,
要複製到核心堆疊的 zx_channel_iovec_t
陣列。不過,
會導致實作策略無法指派一個zx_channel_iovec_t
每個離線 FIDL 物件的項目。
實務上,直接轉換使用者空間可能成效較佳。
是大量的zx_channel_iovec_t
,至少要避免輪班
加入核心不過,為了精簡起見,我們建議使用 8192
限制,直到
如果需要進一步修正
如果實作層級,上限較高,
zx_channel_iovec_t
陣列無法完全填滿核心堆疊。堆疊
緩衝區可用於一般情況,但需要複製到
有足夠的項目時,就會增加大型 (且速度較慢) 緩衝區。
向量化控點
帳號代碼可能相當於 zx_channel_iovec_t
、
或在現有 zx_channel_iovec_t
中連同位元組一起納入。不過
帳號代碼通常會有
小型。為求簡單,帳號代碼會保留在專用陣列中。
支援單一寫入多則訊息
此 RFC 的前一個版本包含支援多重參數的
訊息。zx_channel_write
考慮以下三項提案:
- 平面表示法:將
reserved
欄位重新用於zx_channel_iovec_t
,包含兩個uint16_t
欄位:message_seq
(這些欄位 ,zx_channel_iovec_t
是訊息的一部分) 和handle_count
(號碼buffer
中位元組耗用的控制代碼)。序號為 受限於單調且無間斷。這項限制可啟用 提升核心實作效能,但日後可以縮減 可以視需要使用這個方法與此 RFC 和多重訊息支援 加到現有結構中 - 陣列表示法:表示郵件有外部陣列,
每個訊息都有指向內部 iovecs 陣列的指標。這類似於
通常更熟悉 Linux syscall
sendmmsg
的結構 使用者。雖然陣列陣列的表示法 有證據顯示,由於 間接 (請參閱 CL)。 - 標頭前置字元表示法:緩衝區以標頭開頭,
後面接著 iovec 陣列標頭包含 16 個訊息描述元
每個欄位都只包含
uint16_t
message_size
欄位。這個欄位 判定與zx_channel_iovec_t
撰寫新的電子郵件訊息此示意圖提供了階層結構,但不含 就不需要進行額外的重新導向和複製
在設計討論中,平板代表的原因是 以及效能屬性和簡易度傳達一則有關多重訊息的完整提案 支援服務不在此 RFC 範圍內,請注意,此 RFC 相容 平面式表示法
iovec 專屬系統呼叫
您不必為現有的系統呼叫新增選項
zx_channel_write_iovec
、zx_channel_write_etc_iovec
、zx_channel_call_iovec
可以建立 zx_channel_call_etc_iovec
個系統呼叫不過,您也可以選擇
最好避免系統呼叫次數和認知負載增加
使用者。
zx_channel_read 中的 zx_channel_iovec_t 支援
此 RFC 提議支援 zx_channel_iovec_t
進行管道寫入,但不支援
管道讀取這個程序之所以能有利於
在寫入端執行 iovecs - 避免使用 FIDL 線性化步驟
讓使用者在閱讀方面能有明顯的好處
Rust 繫結可能受益於讀取端 iovec 支援 將緩衝區分成多個小型緩衝區,每個緩衝區都有自己的 擁有權。這有助於建立類似 LLCPP 的繫結變化版本 也就是將緩衝區轉換為輸出物件不過 或是變更 Rust 繫結的短期計畫,以這種方式運作 延遲新增對 iovec 的支援, 表示不需要。
既有藝術品和參考資料
Fuchsia 目前有 zx_stream_readv
和 zx_stream_writev
系統呼叫,
請使用向量化 ioLinux 也提供類似的 readv
和 writev
系統
讀取及寫入檔案描述元的呼叫。