你可能没有听说过 Redox OS,这是一款全部基于 Rust 实现的操作系统。基于 Rust 实现的原因之一是,Rust 用于无与伦比的内存管理机制和线程安全机制。为进一步保证系统安全,其采用了一个更加精简的系统内核,并抵制使用复杂庞大的内核。进一步说,在 UNIX 中有一些类似于驱动的东西需要在内核空间中运行,但是在 Redox OS 中,驱动程序甚至可以在用户空间中运行,而且不会导致计算机系统的宕机。
Redox OS 有一套自己的规则来实现进程与内核之间的通信。这套规则叫做 everything be a URL (一切皆 URL)。这套规则朴素但好用。你可以像这样打开一个带路径的文件 scheme:path
。如果没有文件规则限制,则默认为当前工作目录下,通常表示为 file:
。
什么是一切皆 URL
一切皆 URL 是 Redox 设计规范中一个非常重要的原则。大致意思是,所有 API,设计思路等一整套生态系统都是以 URL 为中心展开,资源左右主要的通信原语。应用与应用直接,与系统之间,与守护进程间等等通信均使用 URL 。举例来说,应用程序不必要创建它们自己专门用来通信的实体。
你可以通用这个规范设计出高一致性、简洁、灵活的接口。
这个规范的作用不会被过度宣扬(这有点超出设计时的初衷了)。这个思路也不是全新创造出来的,Plan9 中就有类似的概念。另外一个成功的概念是 UNIX 中的一切皆文件。
与 ‘一切皆文件’ 的区别
在一切皆文件的概念中,所有类型的设备、进程、内核参数等等都可以在常规的文件系统的中被展现为一个文件。这可能会引发出一些荒诞的事情,例如硬盘中包含了 root 目录的文件系统,根目录 /
中包含了一个叫做 dev
的文件夹,其中包括了含有 root 文件系统的 sda
在内的众多设备文件…… 像这样的情况似乎缺乏了一点逻辑。此外,许多文件属性对许多特殊意义的文件并没有意义,比方说: /dev/null
的大小是多少,或者 sysfs 的配置选项是什么?
相比于一切皆文件的概念,Redox 不会为所有类型的资源来强制实现一个公共可访问的节点树,取而代之的是通过协议来区分的资源。这个方法下 USB 设备将不会展现为文件系统,而是展现为基于协议的一个 scheme ,比如说叫做 EHCI
scheme 。真正地文件将会通过一个叫做 file
的 scheme 来访问。更多内容可以了解 RFC 1630 和 RFC 1738.
一些例子
TCP
这里有一个 TCP 协议结构的例子。
1 | let mut file = File::open("tcp:93.184.216.34:80")?; //example.com |
即便网络支持在别的系统中不太容易实现,但是 redox 中却十分简单。你可以像这样开箱即用,open("tcp:address", O_RDWR)
。
上面这段代码实现了简单的 curls 功能,而且没有依赖任何类库(不像传统意义上的解析 http 协议,更像是一个直接执行 http 请求的库。)
Program IPC
以下是一个 IPC 的例子:
1 | let server = File::open("chan:hello", O_CREAT)?; |
你可以调用 open("chan:name", O_CREAT)
来创建一个服务,然后使用 dup("listen")
来通过连接请求。dup
关键词的含义是赋值文件,但是可以选择采用 scheme 中已经使用过的路径。
Events
这个方案有点特殊,不是因为它有任何特殊的硬编码异常,而是因为它在任何地方都使用,即使在其他方案中也是如此。
事件方案有点类似于 linux 的 epoll 。你可以将写入一个事件到一个实例中,这个实例将会在文件中监听和注册。然后你可以读这个事件,直到事件遇到第一次阻塞的时间为止。
下面有一个 event overhaul RFC 的例子:
1 | const TOKEN_TIME: usize = 0; |