本文說明支援 Fuchsia 時,通常會使用的結構語言。
系統呼叫
Fuchsia 支援的最低語言層級可讓您存取 Zircon 系統呼叫。公開這些系統呼叫,可讓以該語言編寫的程式與核心互動,並透過核心與系統的其他部分互動。
程式無法直接發出系統呼叫。而是透過呼叫 vDSO 中的函式來進行系統呼叫,而 vDSO 是由建立者載入新建立的程序中。
vDSO 的公開進入點定義於 //zircon/vdso。這個檔案會由 zither 工具處理。
非同步
絕大多數 Fuchsia 程式都做為「伺服器」。啟動後,它們會在事件迴圈中等待接收訊息、處理這些訊息 (可能透過將訊息傳送至其他程序),然後返回事件迴圈中休眠。
Fuchsia 事件迴圈的基本建構區塊是通訊埠物件。執行緒可以使用 zx_port_wait 在通訊埠中休眠。核心喚醒執行緒時,會提供封包,這是一種資料結構,說明核心喚醒執行緒的原因。
一般來說,每個執行緒都有一個通訊埠物件,執行緒會在其中休眠,而以您的語言編寫的大量程式碼都需要與該物件互動。語言維護人員通常不會直接公開通訊埠,而是提供程式庫,將通訊埠抽象化並提供非同步等待作業。
大多數非同步等待作業都會在 zx_object_wait_async 中結束。一般來說,port 和 key 引數由程式庫提供,handle 和 signals 引數則由用戶端提供。建立等待時,用戶端通常也會提供上層呼叫 (例如閉包),供程式庫在等待完成時叫用,此時程式庫會使用 key 復原上層呼叫 (例如從雜湊表)。
不需要額外的核心物件,就能從另一個執行緒喚醒執行緒。如要喚醒執行緒,只要使用 zx_port_queue 將使用者封包排入執行緒的通訊埠即可。
範例
- async (C 和 C++)
- fuchsia-async (Rust)
FIDL
Zircon 核心本身主要提供記憶體管理、排程和處理序間通訊。大部分的系統介面並非由核心直接提供,而是透過處理序間通訊提供,通常使用管道。用於處理序間通訊的通訊協定,是以 Fuchsia 介面定義語言 (FIDL) 定義。
FIDL 對語言的支援通常包含兩個部分:
- FIDL 編譯器的語言專屬後端,會以譯文語言產生程式碼。
- 以譯文語言編寫的支援程式庫,由 FIDL 編譯器產生的程式碼使用。
這些部分通常不會內建在語言實作或執行階段中。相反地,程式庫是開發人員程式的一部分,且版本與語言執行階段無關。程式與語言執行階段之間的穩定介面應為系統呼叫,而非 FIDL 通訊協定,這樣開發人員才能獨立選擇 FIDL 通訊協定版本和語言執行階段版本。
在某些情況下,語言執行階段可能需要在內部使用 FIDL。如果發生這種情況,建議您盡可能在語言中向開發人員的程式隱藏這項實作詳細資料。開發人員可能希望使用相同 FIDL 通訊協定的新版本,而不與語言執行階段內部使用的版本衝突。
FIDL 編譯器後端
FIDL 編譯器有一個前端,可用於所有語言,以及多個支援各種語言的後端。前端會產生 JSON 中繼格式,供特定語言的後端使用。
您應該為語言的 FIDL 編譯器建立新的後端。後端可以使用您偏好的任何語言編寫。通常,語言維護者會選擇 Go 或目標語言。官方後端名為 fidlgen_<lang>,位於 //tools/fidl。
產生的程式碼
生成的 FIDL 程式碼會因語言而有很大差異。生成的程式碼通常包含下列類型:
- 資料結構定義,代表 FIDL 語言中定義的資料結構。
- 可將這些資料結構序列化及反序列化為 FIDL 線路格式,以及從該格式反序列化的轉碼器。
- 代表 FIDL 通訊協定伺服器端的虛設常式物件。一般來說,虛設常式物件具有 dispatch 方法,可將從 Zircon 管道讀取的訊息反序列化,並執行間接跳轉至訊息 ordinal 指定的方法實作。
- 代表 FIDL 通訊協定用戶端端的 Proxy 物件。一般來說,對 Proxy 物件呼叫方法會導致訊息序列化,並透過 Zircon 管道傳送。一般來說,Proxy 物件會針對事件訊息提供調度,類似於要求訊息虛設常式中的調度方法。
部分語言會為某些類型的生成程式碼提供多個選項。舉例來說,常見的模式是同時提供「同步」和「非同步」Proxy 物件。同步 Proxy 會使用 zx_channel_call 有效率地寫入訊息、封鎖等待回應,然後讀取回應,而非同步 Proxy 則會使用 zx_channel_write、zx_object_wait_async 和 zx_channel_read,避免在管道的遠端封鎖。
一般來說,我們建議盡可能使用非同步程式碼。許多 FIDL 通訊協定都採用非同步、前饋模式。
支援資料庫
為語言設計產生的程式碼時,請特別注意二進位檔大小。複雜的程式通常會與大量 FIDL 通訊協定互動,每個通訊協定都可能定義許多資料結構和通訊協定。
縮減二進位檔大小的重要技巧之一,是盡可能將程式碼重構至 FIDL 支援程式庫。舉例來說,C 繫結、所有序列化和反序列化邏輯都是由支援程式庫中的常式執行。產生的程式碼只包含一個表格,以精簡形式描述傳輸格式。
一般來說,支援程式庫會疊加在非同步程式庫之上,而非同步程式庫本身並不知道 FIDL。舉例來說,大多數支援程式庫都包含讀取器物件,可管理管道上的非同步等待和讀取作業。接著,產生的程式碼可以限制為序列化、反序列化和調度。
POSIX 樣式 IO
POSIX 樣式的 IO 作業 (例如 open、close、read 和 write) 會疊加在 FIDL 上。如果您的語言具有 C 互通性,可以使用 FDIO 程式庫,將熟悉的 POSIX 作業轉譯為基礎 fuchsia.io FIDL 通訊協定。如果您的語言沒有 C 互通功能,則必須直接與 fuchsia.io 介面,才能提供 POSIX 樣式的 IO。
您可以使用 lib/fdio/unsafe.h 復原檔案描述元的基礎 Zircon 控制代碼。一般來說,程式語言會有一個小型程式庫,疊加在非同步程式庫之上,用於對檔案描述元執行非同步等待。這個程式庫通常會提供較不易出錯的介面,將這些「不安全」的 FDIO 函式抽象化。