Zircon内核概念
介绍
Zircon内核管理许多不同类型的对象。本质上讲,这些对象是能够通过系统调用直接访问,并实现了Dispatcher接口的C++类。对象的实现在kernel/object(英文原文)目录下,它们中许多是自依赖的高层对象,而另外一些是对底层lk原始操作的封装。
系统调用
用户空间代码通过系统调用与内核对象进行交互,以及几乎只能通过句柄对象(Handle
)加以访问。在用户空间中,Handle
通过32位整型(zx_handle_t
类型)来表示。
当系统调用被执行时,内核检查Handle
变量指向的实际句柄是否存在于调用进程的句柄列表中。然后内核进一步检查该Handle
是否具有正确的类型(例如传递一个Thread Handle到需要事件信号的系统调用会导致错误发生),以及Handle
是否对请求的操作具有相应的权限(Right
)。
从访问的角度上看,系统调动可以被细分为如下三大类:
- 没有任何限制的调用。只有少部分调用是属于这一类,如zx_clock_get()和zx_nanosleep()可以被任意线程调用。
- 以
Handle
作为首参数的调用,用以表示它们所操作的对象。绝大多数的调用都是这一类,例如zx_channel_write()和zx_port_queue()。 - 创建新对象的系统调用,不需要以
Handle
作为参数。例如zx_event_create()和zx_channel_create()。这一类调用的访问是受调用Process
进程所在的Job
所控制的(这同时也是它们的限制)。
系统调用由libzircon.so所提供。libzircon.so是由Zircon内核提供给用户空间的”虚拟“共享库,更有名的说法是虚拟动态共享库( virtual Dynamic Shared Object)或者简称为vDSO(英文原文),是由一系列以zx_noun_verb()
或
zx_noun_verb_direct-object()
为名的ELF ABI C函数所组成。
系统调用由syscalls.abigen(英文原文)所定义,并被abigen(英文原文)工具所处理。abigen
将文件和胶水代码一起添加到libzircon
中和内核的libsyscalls
中。
句柄(Handle(英文原文))和权限(Right(英文原文))
每个Object
可以(在一个或多个进程中)有多个不同的Handle
指向它们。
对于所有的Object
,当最后指向它们的Handle
关闭时,该Object
同时也将被销毁,或者放置到结束状态(译者注:类似于Java中的finalize)下,并且这样的操作不可回滚。
可以通过向Channel
写入Handle
的方式,将Handle
从一个Process
移动到另外一个Process
(使用 zx_channel_write()函数),或通过使用zx_process_start()函数,作为新Process
的第一个线程的启动参数的形式传递一个Handle
。
在Handle
或者它所指向的Object
上的操作受到Handle
相关联的权限(Right
)所控制,并且两个指向同一Object
的Handle
可以具有不同的Right
。
zx_handle_duplicate()和zx_handle_replace()调用可被用于获取指向Object
的Handle
参数的额外副本,并以缩小的权限作为可选项。 zx_handle_close()用于关闭Handle
,如果它是所指向的Object
的最后一个句柄,也将同时释放这个Object
。
内核对象ID
在内核中的每个对象都具有”内核对象id”或简称为“koid”。它们是64位无符号整型,用以唯一定位这些对象,并且在系统生命周期内是唯一的,这尤其意味着koid将不会被重用。
有两种特别的koid值:
ZX_KOID_INVALID的值为0,可用做表示”null“的哨兵值。
ZX_KOID_KERNEL只有一个内核,并且具有它自己的koid(译者注:原文为There is only one kernel, and it has its own koid.)。
运行代码:任务(Job),进程(Process)和线程(Thread)
Thread
表示在拥有它们的Process
的地址空间中线程的执行(CPU寄存器,运行栈等)。Process
被Job
所拥有,而后者定义了各种可用资源的上限。Job
又被父Job
所拥有,并一直可以追溯到根任务(Root Job
)。根任务于内核在启动时所创建,并被传递到第一个被执行的用户进程userboot
(英文原文)中。
离开了指向Job
的Handle
,Process
中的Thread
将无法创建其他Process
或Job
。
程序的加载(英文原文)机制由用户空间设施和内核层之上的协议所提供。
请查看:process_create,process_start,thread_create和thread_start。
消息传递:Socket和Channel
Socket
和Channel
都是双向和双端的进程间通信(IPC)相关的Object
。创建Socket
或Channel
将返回两个不同的Handle
,分别指向Socket
或Channel
的两端。
Socket
是面向流的对象,可以通过它读取或写入以一个或多个字节为单位的数据。Short writes(如果Socket的缓冲区已满)和short read(如果请求的字节数量超过缓冲区大小)也同样受到支持。
Channel
是面向数据包的对象,并限制消息的大小最多为64K(如果有改变,可能会更小),以及最多1024个Handle
挂载到同一消息上(如果有改变,同样可能会更小)。无论消息是否满足short write或read的条件,Channel
均不支持它们。
当Handle
被写入到Channel
中时,在发送端Process
中将会移除这些Handle
。同时携带Handle
的消息从Channel
中被读取时,该Handle
也将被加入到接收端Process
中。在这两个时间点之间时,Handle
将同时存在于两端(以保证它们指向的Object
继续存在而不被销毁),除非Channel
写入方向一端被关闭,这种情况下,指向该端点的正在发送的消息将被丢弃,并且它们包含的任何句柄都将被关闭。
请查看:channel_create,channel_read,channel_write,channel_call,socket_create,socket_read和socket_write。
对象(Object)和信号(Signal)
Object
至多可以可包含32个信号(通过zx_signals_t
数据结构和ZX_SIGNAL的定义),它们是表示当前一些状态信息。例如,Channel
和Socket
可为可读(READABLE
)和可写的(WRITABLE
),Process
或Thread
可以为终止(TERMINATED
)状态等等。
线程可以等待一个或多个Object
被信号激活。
请查看signals(英文原文)以了解更多的信息。
等待:等待一次,等待多次和端口(Port)
Thread
可以使用zx_object_wait_one()来等待某个句柄被收到信号,或者使用zx_object_wait_many()方法来等待多个句柄收到信号。两种调用都允许设置超时点,即没有信号待处理,它们也会因超时而返回。
如果Thread
需要等待大量的句柄时,一种更高效的方式是使用Port
。Port
是一种其他对象可以加以绑定的Object
,绑定的结果是当Single
被发送到Port
上时,Port
将会接收到包含这些待处理Signal
信息的数据包给Thread
作处理。
请查看:port_create,port_queue,port_wait和port_cancel。
事件(Event)和事件对(Event Pair)
Event
是一种仅包含活跃Singal
的集合的最简单Object
。
Event Pair
是一对可相互信号通知的Event
组合。Event Pair
的一个有用性质是当其中一个被销毁(指向它的所有Handle
均已关闭)时,另一个事件将接收PEER_CLOSED
信号。
请查看:event_create和eventpair_create。
共享内存: 虚拟内存对象(VMO)
虚拟内存对象表示一组物理内存页,或者是潜在的内存页(例如将被按需惰性创建/填充)。
VMO可以通过zx_vmar_map()被映射到某个Process
的地址空间,或者通过zx_vmar_unmap()解除映射。这些映射页的权限可通过zx_vmar_protect()函数进行调整。
VMO可通过zx_vmo_read()和zx_vmo_write()操作对它们进行直接的读写操作。因此,通过一次合并操作可以避免映射到地址空间的开销,例如”创建VMO,向其写入数据集后,传入另一进程供其使用“。
地址空间管理
虚拟内存地址区域(Virtual Memory Address Regions,即VMAR)提供了管理进程地址空间的抽象。在进程创建时,根VMAR的句柄被提供给进程的创建者。该句柄指向一个涵盖整个地址空间的VMAR,该空间可通过zx_vmar_map()和zx_vmar_allocate()接口进行分割操作。同时,zx_vmar_allocate()可以被用作生成新的VMAR(被称为子区域或子代)以将地址空间的多个部分组合在一起。
请查看:vmar_map,vmar_allocate,vmar_protect,vmar_unmap和vmar_destroy。
快速用户区互斥锁(Futex)
Futex
是用于在用户空间实现高效(例如,内核中的Mutex
只需要在竞争处一次调用)同步原子操作的内核原语。通常情况下,只有实现标准库的开发者对它们感兴趣。在Zircon的libc和libc++中,提供了基于Futex的mutex和condition变量的实现,包括C11,C++和pthread API等版本。