我認爲微內核的意義(2)-分析zircon

 簡介

內核消息是一些不同類型的對象。這些對象可以直接通過syscall調用,並且這些對象是C++的類,由調度接口實現,位於kernel/object目錄。許多是自包含的高階對象,一些是包含低階的lk原語。

syscall

用戶空間代碼與內核對象的交互通過syscall,大多數僅通過Handle。在用戶空間,一個Handle是32位整型(zx_handle_t)。進程的Handle存在於表中,表中的Handle具有參數,當進程發起syscall,內核會檢查發起調用的進程的實際Handle的參數。內核進一步檢查Handle類型正確(傳遞線程Handle給需要事件Handle的syscall將會引起錯誤),並且Handle必須要有所請求的操作的所需權限。

syscall從訪問的角度可分爲3類:

1.沒有限制(很少),例如zx_clock_get()、zx_nanosleep()可以被任何線程調用。

2.需要Handle作爲第一參數的,表示其將要操作的對象(很多且主要),例如zx_channel_write()和zx_port_queue()。

3.創建新對象但不需要Handle的,比如zx_event_create()、zx_channel_create()。這些syscall的調用由進程所屬的Job控制。

syscall由libzircon.so提供,libzircon.so是一個虛擬的共享庫,由Zircon內核提供到用戶空間(詳見virtual Dynamic Shared Object or vDSO)。他們是C ELF ABI函數,格式爲zx_noun_verb()或zx_noun_verb_direct-object()。

系統調用由syscalls.abigen定義,由abigen工具處理爲libzircon中的包含文件和粘合代碼,以及內核的syscall庫。

Handles和權限

對象可能被關聯到多個Handles(在1或多個進程裏)。

對於幾乎所有對象,當最後一個關聯它的Handle被關閉,這個對象會被銷燬或放入不可逆的最終狀態。

Handles可以通過寫入Channel實現從一個進程移動到另一個進程;也可以通過zx_process_start()來將Handle作爲一個新進程第一線程的參數傳入。

對Handle或對象的操作由與Handle相關的權限支配。兩個關聯同一對象的Handles可能有不同的權限。

syscall的zx_handle_duplicate()和zx_handle_replace()可能被用於得到相同對象的額外Handles,獲得的Handle可以與之前的一樣,也可以減少權限。zx_handle_close()會關閉Handle,關閉Handle會釋放關聯的對象,如果被關閉的Handle是最後一個與對象相關聯的Handle,對象將會被釋放。zx_handle_close_many()用於關閉一組Handles。

內核對象的ID

每一個內核中的對象都有一個ID,是64位無符號整型,可以用於識別對象,並且在系統運行中是唯一的。這也意味着內核對象ID不可重用。

有兩個特別的對河對象ID:ZX_KOID_INVALID是0,被用作哨兵;ZX_KOID_KERNEL只有一個內核,有其自己的ID。

運行代碼:Jobs,進程和線程

Jobs含有進程,並定義了多樣的資源限制。Jobs歸屬於父Jobs,一直到根Job,根Job由內核創建並送到userboot。

沒有Job Handle,進程裏的線程是不可能創建另外的進程或Job的。

程序的加載有用戶空間實現。

消息傳遞:Sockets和通道

Socket和通道都是IPC對象,都是雙端雙向。創建一個Socket或Channel將會返回兩個Handles分別關聯到對象的端點。

Socket是面向流的,數據作爲1或多個bytes的單元寫入或獨處。短寫(緩存不夠)和短讀(要讀的比緩存中的多)都是支持的。

通道是面向數據報的,有最大消息長度64K(可以配置的更小),一個消息可以最多附屬1024個Handles。不支持短讀短寫,一個消息要不就是合適,要不就是不合適。

當一個消息寫入通道,其就會被從發送進程中切除,當接收進程把一個消息和Handle從通道中讀出,這個Handles就會被加入到接收進程。在這兩個事件期間,Handles會一直存在,除非通道另一端的接收進程關閉了端點,其中的所有Handles都關了。

對象和信號

對象最多可以有32個信號(由zx_signals_t類型和ZX_SIGNAL宏定義),這些信號可以代表一部分對象的當前狀態:比如通道和Socket所處的可讀或可寫的狀態;進程和線程則可能是TERMINATED。還有其他狀態不列舉。

線程可能等一到多個對象的信號來喚醒。

等待:等待一或多或端口

一個線程可能使用zx_object_wait_one()或zx_object_wait_many()陷入等待一到多個信號(一或多個Handles的);這兩個syscalls都可以設置超時。

如果一個線程要等待大量的Handles,更高效的做法是使用端口;端口是一個可以綁定其他對象的對象,當信號插入到對象,端口會收到一個包含信號源信息的包。

事件和事件對

事件是最簡單的對象,除了採集活躍信號外沒有其他動作。

一個事件對是一對可以互相發出信號的事件。一個有用的屬性就是,當一個事件對的一端關閉(所有關聯的Handles都關閉),另一端就會發生PEER_CLOSED信號。

共享內存:虛擬內存對象

虛擬內存對象表示一組內存物理頁面(或等待缺頁中斷建立映射的頁面)。

zx_vmar_map()和zx_vmar_unmap()分別可以將其映射進入進程或斷開映射。映射頁的權限可以用zx_vmar_protect()調整。

虛擬內存對象也可以通過zx_vmo_read()和zx_vmo_write()直接讀或寫入。用映射的方式使用可以避免寫入和讀取,直接在其上操作,併發送到其他進程。

地址空間管理

虛擬內存地址克難攻堅提供管理進程內存空間的抽象。在進程創建時,根虛擬內存地址空間的Handle會提供給進程創建者,這一Handle會關聯到一個VMAR,這個VMAR跨有整個地址空間;這個空間可以通過zx_vmar_map()和zx_vmar_allocate()簡歷到物理地址的映射。zx_vmar_allocate()可以被用於生成另外一個虛擬內存地址空間,被稱作子空間或孩子,可以用於將地址空間的一部分組合在一起。

Futexes

Futexes是內核原語,用於用戶空間原子操作,實現高效的同步原語;比如Mutexes,只需要在競爭的場合發起一個syscall即可;一般來說,他們只被是現在標準庫中。Zircon的libc和libc++爲互斥、條件變量等提供C11、C++和線程的API,基於Futexes實現。

發佈了37 篇原創文章 · 獲贊 4 · 訪問量 3391
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章