Fuchsia系列博客(三) Zircon內核核心概念

  • 翻譯自(不是嚴格翻譯):

fuchsia.googlesource.com

介紹

Zircon內核負責管理大量不同類型的對象.

那些實現了Dispather介面的對象可以通過系統調用直接訪問, 這些對象在kernal/object目錄下, 包括許多自包含的高級對象, 和一些對lk原語的封裝.

系統調用(System Call)

用戶空間的代碼通過系統調用與內核對象交互, 甚至可以說, 絕大多數是通過Handles(句柄).(譯者按: 下文中, Handle一詞一律不翻譯.)Handle實際上是一個32bit 的整數(zx_handle_t類型).

在系統調用被實際執行前, 內核將進行三項檢查.

  1. 檢查Handle參數是否指向調用process進程的Handle表中存在的實際句柄.
  2. 檢查Handle的類型是否正確. (例如:將Thread Handle傳給需要Event Handle的系統調用會導致錯誤.)
  3. 檢查Handle是否具有所請求的操作許可權.

從訪問限制的角度看, 系統調用分為三大類:

  1. 無限制系統調用. 可以被任何thread(線程)調用, 極少數的系統調用屬於這一類, 例如:zx_clock_get()zx_nanosleep().
  2. 消費一個Handle的系統調用. Handle作為第一個參數, 代表系統調用作用的對象. 絕大多數的系統調用屬於該類, 例如:zx_channel_write()zx_port_queue().
  3. 無需Handle並創造新對象的系統調用. 他們的調用以及訪問限制由包含該process(進程)的Job(作業)控制.例如:zx_event_create()zx_channel_create().

系統調用由libzircon.so提供, libzircon.so是一個由內核提供的"虛擬"共享庫, 也被稱之為virtual Dynamic Shared Object 或者vDSO. 系統調用都是C ELF ABI形式的函數: zx_名詞_動詞或者zx_名詞_動詞_直接對象.

系統調用由syscall.abigen定義, 並且由abigen tool處理頭文件和libzircon中與內核libsyscalls連接的膠水代碼.

Handles(句柄) 和 Rights(許可權)

  1. 可以有很多分佈在一個或多個進程(process)中的Handle指向同一個對象.
  2. 對於絕大多數對象來說, 最後一個指向他的Handle被關閉, 該對象也隨之消亡, 抑或進入一種無法撤銷的最終狀態.
  3. 有兩種方式把句柄在進程之間轉移, 第一種是調用zx_channel_write()把Handle寫入Channel(通道), 另一種方法是調用zx_process_start(), 把這個Handle傳遞給新進程的第一個線程.
  4. Rights負責管理相關Handle和Object可能進行的任何行為, 指向同一對象的不同Handle完全可能用有不同的許可權.
  5. zx_handle_duplicate()zx_handle_replace()系統調用可以產生指向該對象的新的Handle, 並且可以選擇性減少新Handle的許可權.
  6. zx_handle_close()負責關閉Handle, 如上所述, 該方法也將銷毀對象, 如果關閉Handle後再沒有Handle持有該對象. zx_handle_close_many()與其相似, 只是關閉一個Handle數組中的所有Handle.

內核對象ID (Kernel Object IDs)

每個對象都有個內核對象ID, 簡稱koid. 這是一個64位整數, 是對象的唯一標識符, 並且在系統運行的週期內是唯一的. 這意味著"koid"永遠不會被重用.(譯者按: 真的不會被用完嗎? 0.0)

有兩個特殊的koid值: ZX_KOID_INVALID: 值是0, 用來做null. ZX_KOID_KERNEL: 內核自己的唯一koid. 內核只用63個位(真的是很多了)生成koid. 用戶可以通過設置最高有效位, 分配剩餘的koid. 內核分配koid的順序沒有被指定, 並且可能發生變化. 人工分配的koid提供了更多可能:例如辨別人工對象, 跟蹤虛擬線程, 這些都可以被各種工具使用. 而對於每個程序如何分配人工koid, 本文檔不做任何限制和規則約束.

運行中的代碼: 作業(Jobs), 進程(Processes)和線程(Threads)

線程代表地址空間中實際執行的線程(CPU 寄存器, 棧等), 線程的地址空間被他們所在的進程擁有.

進程又由作業擁有, 作業定義了各種各樣的資源限制. 作業又被它的父作業擁有, 層層傳遞, 直到根作業(Root Job). 根作業在系統啟動時由內核創建, 進而傳遞給第一個用戶空間進程--userboot. 沒有作業的Handle, 進程中的線程不可能創建另一個進程或者另一個作業. 程序如何載入由內核空間上層的用戶空間設施和協議規定. 請參閱:zx_process_create(), zx_process_start(), zx_thread_create()zx_thread_start().

消息傳遞: 套接字(Sockets)和通道(Channels)

套接字和通道都是用於雙向通信的IPC對象, 創建套接字或者通道將返回兩個對象, 一邊一個.

套接字是面向流的編程模型, 允許短讀和短寫, 數據以一個或多個位元組作為單元傳輸. 通道是面相數據報的編程模型, 擁有最大長度限制ZX_CHANNEL_MAX_MSG_BYTES, 還擁有消息句柄數量限制, 即ZX_CHANNEL_MAX_MSG_HANDLES. 不支持短寫和短讀 -- 嚴格判定每個消息是否合適. 當Handle被寫入通道時, 他們從發送端進程移除. 當Handle從通道讀取時, 他們被加入到接收端進程. 在傳輸過程中, Handle並未消失, 這意味著它指向的對象仍舊存在. 然而, 如果通道的終點被關閉, 傳輸中的消息將會被丟棄, 所有指向該消息的句柄都會被關閉.

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

對象(Objects)和信號(Signals)

對象有至多32種信號(zx_signals_t類型, 由ZX_SIGNAL定義), 這些信號代表對象當前狀態的信息. 例如: 通道(Channel)和套接字(Socket), 可能是READABLE或者WRITABLE的. 進程(Process)和線程(Thread)可以是TERMINATED, 等等...

線程可以等待一個或多個對象上的信號來激活自己. 參見Signals獲取更多信息.

等待:等待一個, 等待許多, 等待埠

線程可以使用zx_object_wait_one()等待一個信號Handle, 或者用zx_object_wait_many()等待一組信號Handle.

這兩種方法都允許超時設置, 一旦超時, 即使沒有響應信號, 方法也會返回.

由於timer slcak(計時器鬆弛)的存在, 超時設置將會有誤差, 並不一定在設置的時間返回. 詳情請見timer slack.

如果一個線程想要等待大量的Handle, 那不如使用埠(Port). 埠是一個對象, 可以被其他對象綁定, 這樣, 當其他對象上的信號到達時, 埠就會收到與這些信號的信息相關的數據包.

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

事件 (Events), 事件對 (Event Pairs)

事件是最簡單的對象,除了其活動信號集合之外沒有其他狀態。

事件對是可以相互發信號的一對事件之一。事件對的一個有用屬性是當一側消失(所有句柄都已關閉)時,PEER_CLOSED信號在另一側被斷言。(譯者按: 量子糾纏?)

請參閱: zx_event_create()zx_eventpair_create().

共享內存: 虛擬內存對象(VMO)

虛擬內存對象代表一組物理內存頁面,或"潛在"的頁面(可以按需創建/填充的頁面).

虛擬內存對象可以通過zx_vmar_map()來映射到進程的地址空間, 用zx_vmar_unmap()取消該映射. 被映射頁面的許可權可由zx_vmar_protect()來調整.

VMO也可以通過zx_vmo_read()zx_vmo_write()直接讀取和寫入. 因此,對於一次性操作, 如"創建一個VMO, 將數據集寫入其中, 並將其交給另一個進程使用", 可以避免將它們映射到地址空間的成本。

地址空間管理

虛擬內存地址區域(VMAR)提供了管理進程地址空間的抽象。在進程創建時,將向進程創建者提供root VMAR的句柄。該句柄指的是跨越整個地址空間的VMAR。這個空間可以通過zx_vmar_map()zx_vmar_allocate()介面進行分割. zx_vmar_allocate()可以用於生成新的VMAR(稱為subregionschildren), 這可以將地址空間的某些部分組合在一起。

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

Futexes

Futexes是與用戶空間原子操作一起使用的內核原語, 用於實現高效的同步原語 -- 例如, 競爭情況下的互斥鎖實現, 只需要一個系統調用. 通常只有標準庫的實現者對他們感興趣. Zirconlibclibc++為互斥體, 條件變數等以Futexes的形式提供了C11, C ++pthread的API.

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

推薦閱讀:

相關文章