如何建構 Fuchsia 支援的語言

本文件將說明支援 Fuuchsia 時的結構語言。

系統呼叫

某種語言中 Fuchsia 支援的最低級別,提供 Zircon 系統呼叫的存取權。公開這些系統呼叫可讓使用該語言編寫的程式與核心互動,以及與系統的其餘部分互動。

程式無法直接發出系統呼叫,而是藉由呼叫 vDSO 中的函式進行系統呼叫,該函式會載入其建立者新建立的程序中。

vDSO 的公開進入點定義於 //zircon/vdso 中。這個檔案會由 zither 工具處理。

非同步

絕大多數的 Fuchsia 程式都做為「伺服器」。啟動之後,他們會等待事件迴圈中接收訊息、處理這些訊息 (可能會傳送訊息到其他程序),然後在事件迴圈中回到休眠狀態。

Fuchsia 中事件迴圈的基本構成要素是通訊埠物件。執行緒可以使用 zx_port_wait 休眠在通訊埠中。核心喚醒執行緒時,核心會提供「封包」,這種資料結構可說明核心喚醒執行緒的原因。

一般來說,每個執行緒都有一個用來睡眠的通訊埠物件,這需要與以您的語言編寫的大量程式碼互動。語言維護人員通常會提供抽象的程式庫,並提供非同步的等待作業,而不會直接公開通訊埠。

大部分的非同步等待作業是在 zx_object_wait_async 中結束。一般而言,portkey 引數是由程式庫提供,handlesignals 引數則是由用戶端提供。建立等待時,用戶端還會提供啟動呼叫 (例如關閉),讓程式庫在等待完成時叫用,此時程式庫會使用 key 復原向上呼叫 (例如從雜湊資料表)。

無需額外的核心物件就能從其他執行緒喚醒執行緒。只要使用 zx_port_queue,就能將使用者封包排入執行緒的佇列,藉此喚醒執行緒。

範例

FIDL

Zircon 核心本身主要提供記憶體管理、排程和處理序間通訊。大量系統介面並非直接由核心提供,實際上是透過處理序間通訊提供,通常使用管道。用於處理序間通訊的通訊協定在 Fuchsia 介面定義語言 (FIDL) 中定義。

語言 FIDL 支援通常包含兩個部分:

  1. FIDL 編譯器的語言專屬後端,以目標語言產生程式碼。
  2. 以譯文語言編寫的支援資料庫,由 FIDL 編譯器產生的程式碼使用。

這些片段通常未內建於語言實作或執行階段中。反之,程式庫是開發人員程式的一部分,而且與語言執行階段無關。程式和語言執行階段之間的穩定介面應為系統呼叫 (而非 FIDL 通訊協定),以便開發人員獨立選擇其 FIDL 通訊協定的版本及其語言執行階段的版本。

在某些情況下,語言執行階段可能需要在內部使用 FIDL。如果發生這種情況,請盡可能以您的語言,在開發人員程式中隱藏這項實作詳細資料。開發人員可能會想要使用相同 FIDL 通訊協定的較新版本,而不與語言執行階段內部使用的版本相衝突。

FIDL 編譯器後端

FIDL 編譯器具有單一前端,可用於所有語言和多個支援多種語言的後端。前端會產生由語言專屬後端使用的 JSON 中繼格式

您必須為自己的語言建立 FIDL 編譯器的新後端。您可以使用您偏好的任何語言編寫後端。一般來說,語言維護者選擇「Go」或「譯文語言」。官方後端的名稱為 fidlgen_<lang>,可在 //tools/fidl 中找到。

產生的程式碼

產生的 FIDL 代碼在每種語言之間有很大差異。一般來說,產生的程式碼會包含以下幾種類型的程式碼:

  • 代表 FIDL 語言中定義的資料結構的資料結構。
  • 可在 FIDL 傳輸格式中序列化和反序列化這些資料結構的轉碼器。
  • 代表 FIDL 通訊協定的伺服器端的虛設常式物件。虛設常式物件通常具有 dispatch 方法,可反序列化從 Zircon 管道讀取的訊息,並且間接執行訊息「一般」指定方法的實作。
  • 代表 FIDL 通訊協定用戶端結束的 Proxy 物件。一般而言,對 Proxy 物件進行方法呼叫會導致訊息序列化,並透過 Zircon 管道傳送。一般而言,Proxy 物件會為事件訊息提供「分派」,類似於要求訊息的虛設常式方法中的分派方法。

針對這類產生的程式碼,某些語言提供多種選項。例如,常見的模式是同時提供同步非同步 Proxy 物件。同步 Proxy 會利用 zx_channel_call,有效率地撰寫訊息、封鎖等待回應,然後讀取回應;非同步 Proxy 則會使用 zx_channel_writezx_object_wait_asynczx_channel_read,避免在管道的遠端端遭到封鎖。

一般而言,我們建議盡量使用非同步程式碼。許多 FIDL 通訊協定都是設計用於非同步的前饋模式。

支援資料庫

為您的語言設計產生的程式碼時,請特別留意二進位檔大小。精密的程式通常會與大量 FIDL 通訊協定互動,而每個通訊協定都能定義許多資料結構和通訊協定。

減少二進位檔大小的重要技巧,是盡可能將最適當的程式碼納入 FIDL 支援資料庫中。舉例來說,C 繫結會由支援資料庫中的日常安排執行所有序列化和去序列化邏輯。產生的程式碼只包含一張表格,說明精簡格式的傳輸方式。

一般來說,支援資料庫會分層在 async 程式庫上,因為此程式庫本身不知道 FIDL。舉例來說,大部分的支援程式庫都包含一個「讀取者」物件,這個物件可管理管道上的非同步等待與讀取作業。接著,就可以限制產生的程式碼只能進行序列化、去序列化和分派。

POSIX 樣式 IO

POSIX 樣式的 IO 作業 (例如openclosereadwrite) 會在 FIDL 之上疊加。如果您的語言具有 C 互通性,您可以使用 FDIO 程式庫,將慣用的 POSIX 作業轉換為基礎 fuchsia.io FIDL 通訊協定。如果您的語言沒有 C 互通性,則必須直接透過 fuchsia.io 介面提供 POSIX 樣式的 IO。

您可以使用 lib/fdio/unsafe.h 復原檔案描述元的基礎 Zircon 控制代碼。一般而言,語言會有一個小型程式庫,這些程式庫位於 async 程式庫上方,以便對檔案描述元執行非同步等待。這個程式庫通常會提供較不容易出錯的介面,以便提取這些「不安全」的 FDIO 函式。