3.122. Zircon架构简单分析1:Overview

有朋友让我评价一下Zircon的可用性,所以我花了几天时间大概看了一下这个系统的构架相关信息。对它的判断我私下和他说,但看到的基础事实我记录在这里,供其他也有兴趣的同行一起探讨。

先运行一下看看系统成熟度。按文档的建议(https://fuchsia.googlesource.com/zircon/+/HEAD/docs/getting_started.md),git clone,安装依赖,build arm64版本(现在只支持x64和arm64两个平台),用qemu运行,系统可以轻松模拟起来:

../_images/zircon1.jpg

这不是个标准的Unix目录结构,但形式类似。大部分目录都还是空的,主要的命令在/boot下,这是一个内置的只读文件系统,在编译内核的时候用lz4压缩直接放到加载镜像中,启动完成后mount成文件系统,提供最基础的用户支持。我把所有命令都运行了一遍。看起来,很多命令还不稳定,一言不合就coredump:

../_images/zircon2.jpg

从代码上看,内核主要是C++写的,系统调用(参考build-arm64/gen/global/include/zircon/zx-syscall-numbers.h)主要包括这些类型:

clock,sleep,handle,object,channel,socket,thread,process,task,event,futex,port,time,vmo,vmar,prng,fifo,trace,interrupt,pci,pager。

大部分从名字上可以猜出提供什么功能。我解释其中几个关键的:

object是对象,类似微软DCOM中的IUNKNOWN,本质是一个C++的类,内核中的各种管理对象,都是object,内部通过koid索引,用户态通过handle来访问它,handle索引没有了,object就自动释放了。这提供最基础的名称服务。当你创建对象(比如创建线程)你得到一个handle,把handle通过channel等手段传递出去,就产生新的channel索引,这样通讯就建立起来了。

channel和socket是IPC,一个提供报文式通讯,一个提供流式通讯。

Job、Task、Process和Thread是调度概念,Job是进程组(控制权限和总体资源),Process是进程(控制独立资源),Thread是线程(控制调度)。Task是三者的抽象,比如,你可以用zx_task_kill(handle)杀掉任何一个对象。这个进程的对外接口做得挺有意思的,我们下一篇再来分析。

vmo和vmar提供内存服务。从vma的定义可以看出这里的思路:vmo代表一组物理内存,可以被vmap等系统调用映射到进程空间中被一个或者多个进程使用。而vmar提供进程空间的管理服务。由此可以初步猜测,系统会认为大数据流是通过类似Android的Binder+SurfaceFlinger那样的IPC加共享内存来完成了。

系统调用中包含pci和interrupt的接口,基本上可以猜测这是通过用户态的进程map bar空间,然后等待中断的形态来完成的。

(提示一句:由于代码比较新,现在找代码特别容易,知道系统调用的名字,找sys_XXXX,基本上就找到入口了。我都是基于入口的参数猜具体的设计目标的)

系统调用使用了vdso技术,直接从内核中提供出来(libzircon.so),不需要libc来提供了。

从系统调用就可以看出,传统的POSIX程序和Linux内核驱动都不要指望可以无缝迁移过来(这是和QNX很大的不同,QNX上几乎所有的Unix程序都可以直接迁移的)

它的用户态程序大概是这个样子的(看system/uapp目录可以找到很多)::

zx_status_t ZirconDevice::CallDevice(const zx_channel_call_args_t& args, uint64_t timeout_msec) {
    uint32_t resp_size;
    uint32_t resp_handles;
    zx_time_t deadline;

    if (timeout_msec == ZX_TIME_INFINITE) {
        deadline = ZX_TIME_INFINITE;
    } else if (timeout_msec >= std::numeric_limits<zx_time_t>::max() / ZX_MSEC(1)) {
        return ZX_ERR_INVALID_ARGS;
    } else {
        deadline = zx_deadline_after(ZX_MSEC(timeout_msec));
    }

    return zx_channel_call(dev_channel_, 0, deadline, &args, &resp_size, &resp_handles);
}

设备无关的就是标准的C/C++接口,设备相关的主要是通过文件系统提供名称服务找到对方的进程,然后通过IPC服务通讯获得数据。

到此为止,可以看到Zircon的心的很大的,是打算彻底抛弃Unix世界重头来的,这也大大增加了它失败的可能性。