Zircon 核心概念

說明

核心可管理多種不同類型的物件。可透過系統呼叫直接存取的 C++ 類別,會實作調度工具介面。在核心/物件中實作。許多是獨立獨立的高層級物件。

系統呼叫

使用者空間程式碼會透過系統呼叫與核心物件互動,在近乎完全透過帳號代碼互動。在使用者空間中,帳號代碼會以 32 位元整數 (類型 zx_handle_t) 表示。執行 syscall 時,處理參數的核心檢查會參照呼叫程序的控點資料表中的實際控制代碼。核心會進一步檢查控點的類型是否正確 (將執行緒控點傳遞至需要事件處理常式的系統呼叫會導致錯誤),以及該控點具備所要求作業的必要權限。

系統呼叫可分為三大類別,從存取點開始:

  1. 沒有限制的呼叫,只有極少數的呼叫,例如 zx_clock_get_monotonic()zx_nanosleep() 都可以由任何執行緒呼叫。
  2. 採用帳號代碼做為第一個參數的呼叫,指出會執行的物件。這些呼叫最常用於,例如 zx_channel_write()zx_port_queue()
  3. 建立新物件但未採用帳號代碼的呼叫,例如 zx_event_create()zx_channel_create()。這些存取權 (以及這類限制) 的存取權是由包含呼叫程序的 Job 所控管。

系統呼叫由 libzircon.so 提供,這是 Zircon 核心提供給使用者空間的「虛擬」共用資料庫,也稱為「虛擬動態共用物件」或 vDSO。這些是 zx_noun_verb()zx_noun_verb_direct-object() 形式的 C ELF ABI 函式。

系統呼叫會在 //zircon/vdso 中以自訂的形式定義。這些定義會先由 fidlc 處理,再由 zither 處理,後者會從 fidlc 取得 IR 表示法,並輸出用於 VDSO 和核心等的各種格式。

帳號代碼權利

物件可能會有在一或多個「程序」中參照的多個帳號代碼,

對絕大多數的物件而言,在參照物件的最後一個開啟控點關閉時,物件會遭到刪除,或進入無法復原的最終狀態。

您可以使用 zx_channel_write() 將帳號代碼寫入頻道,或是使用 zx_process_start() 將帳號代碼做為新程序中第一個執行緒的引數,轉移至其他處理程序。

對於控點或物件參照的物件可執行的操作,則受該帳號代碼相關「權利」所規範。如果兩個控點參照相同的物件,可能會擁有不同的權利。

zx_handle_duplicate()zx_handle_replace() 系統呼叫可用於取得其他控點,參照與傳入的帳號代碼相同的物件,可選擇以減少權限。zx_handle_close() 系統呼叫會關閉控點,並釋出其參照的物件 (如果該控點是該物件的最後一個帳號代碼)。zx_handle_close_many() 系統呼叫同樣關閉控點陣列。

核心物件 ID

核心中的每個物件都有一個簡稱的「核心物件 ID」或「koid」。這是 64 位元的無正負號整數,可用於識別物件,而且在執行系統的生命週期中不會重複。具體來說,亦即絕不會重複使用 Kotlin。

以下是兩種特殊的 koid 值:

ZX_KOID_INVALID:這個值值為零,可做為「空值」傳送參數。

ZX_KOID_KERNEL:只有一個核心,且有自己的 koid。

核心產生的 Kotlin 僅使用 63 位元 (非常充足)。這會透過設定最巨量的位元設定,預留空間供開發人員分配。核心產生 Kotlin 的分配順序未指定,隨時可能有所變更。

人工輔助系統支援各種作業,例如識別人工物件,例如追蹤中的虛擬執行緒,以及供工具使用。人為對各計畫的分配方式,本文件未強制規定任何規則或慣例。

執行程式碼:工作、程序和執行緒。

執行緒代表在相同位址空間中的執行作業 (CPU 註冊、堆疊等) 執行緒,在其存在的程序所擁有的位址空間中。程序由工作擁有,可定義各種資源限制。工作由父項工作擁有,一直到根 Job 在啟動時由核心建立,並傳遞至 userboot (開始執行第一個使用者空間程序)。

如果沒有工作帳號代碼,程序中的執行緒就無法建立其他程序或其他工作。

程式載入是由核心層上方的使用者空間設施和通訊協定提供。

請參閱:zx_process_create()zx_process_start()zx_thread_create()zx_thread_start()

訊息傳遞:通訊端和管道

通訊端和通道都是雙向和雙頭的 IPC 物件。建立通訊端或管道時,系統會傳回兩個控制代碼,一個參照物件的各個端點。

通訊端採用串流導向,資料可能會以一或多個位元組為單位寫入或讀取。在通訊端的緩衝區已滿時,可能會需要短暫寫入,如果要求的資料比緩衝區中還多,則可能會需要短暫讀取。

管道是以資料圖表為導向,且訊息大小上限是由 ZX_CHANNEL_MAX_MSG_BYTES 指定,而且最多可在訊息中附加 ZX_CHANNEL_MAX_MSG_HANDLES 帳號代碼。這類郵件不支援短時間讀寫,無論訊息大小是否合宜。

帳號代碼寫入頻道後,就會從傳送程序中移除。 從頻道讀取含有帳號代碼的訊息時,系統會將帳號代碼加入接收程序。這兩個事件之間,控點會持續存在 (確保它們所參照的物件持續存在),除非這些物件寫入管道的結尾已關閉。此時,指向該端點的訊息會遭到捨棄,且包含的任何帳號代碼都會關閉。

請參閱:zx_channel_create()zx_channel_read()zx_channel_write()zx_channel_call()zx_socket_create()zx_socket_read()zx_socket_write()

物件和信號

物件最多可以有 32 個信號 (以 zx_signalst 類型和 ZXSIGNAL 定義表示),這是與目前狀態相關的資訊。管道和通訊端例如 READABLE 或 WRITABLE。處理程序或執行緒可能會終止。依此類推。

執行緒可能會等待一或多個物件上的信號啟用。

詳情請參閱信號

等待:等待一、多等以及通訊埠

執行緒可以使用 zx_object_wait_one() 等待單一控制代碼啟用信號,或使用 zx_object_wait_many() 等待多個控點上的信號。這兩種呼叫都允許設定逾時時間,之後即使沒有任何待處理的信號,也會回傳。

逾時可能會依照計時器迴圈安排與指定的期限差。詳情請參閱計時器腳架

如果 Thread 正等待大量控點,使用通訊埠會更有效率。通訊埠是其他物件可能繫結的物件,因此當這些物件宣告信號時,通訊埠會收到含有待處理信號相關資訊的封包。

請參閱:zx_port_create()zx_port_queue()zx_port_wait()zx_port_cancel()

事件、事件組合。

事件是最簡單的物件,除了擁有的有效信號集合外,沒有任何其他狀態。

「事件組合」是一組「事件」之一,可能會彼此信號。事件組合的一個實用屬性是,當一對的其中一側消失 (所有控制代碼均已關閉) 時,系統就會在另一側宣告 PEER_CLOSED 信號。

請參閱:zx_event_create()zx_eventpair_create()

共用記憶體:虛擬記憶體物件 (VMO)

虛擬記憶體物件代表一組記憶體的實體頁面,或代表頁面的潛在 (延遲建立/填入)。

這些物件可能透過 zx_vmar_map() 對應至 Process 的地址空間,並與 zx_vmar_unmap() 取消對應。系統會使用 zx_vmar_protect() 調整對應頁面的權限。

您也可以直接使用 zx_vmo_read()zx_vmo_write() 讀取及寫入 VMO。因此,對於「建立 VMO、將資料集寫入資料集,並把資料集交給其他程序使用」這類單次作業,可能會避免浪費至位址空間的成本。

位址空間管理

虛擬記憶體位址區域 (VMAR) 提供管理程序位址空間的抽象化機制。在程序建立時,系統會將根 VMAR 的控制代碼提供給程序建立者。這個控點是指橫跨整個位址空間的 VMAR。這個空間可以透過 zx_vmar_map()zx_vmar_allocate() 介面留存。zx_vmar_allocate() 可用來產生新的 VMAR (稱為子區域或子項),可用於將位址空間的一部分分組。

請參閱:zx_vmar_map()zx_vmar_allocate()zx_vmar_protect()zx_vmar_unmap()zx_vmar_destroy()

家具行

「Futexes」是核心基本功能,可與使用者空間原子作業搭配使用來實作有效的同步基本功能。舉例來說,互斥鎖 (互斥鎖) 只需要在案例下進行系統呼叫。通常只想實作標準程式庫的實作項目。Zircon 的 libc 和 libc++ 提供 C11、C++ 和 pthread API,適用於互斥鎖、條件變數等,以 Futexes 的方式實作。

請參閱:zx_futex_wait()zx_futex_wake()zx_futex_requeue()