|
|
|
|
@ -14,7 +14,13 @@
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
简单来说:
|
|
|
|
|
这三个重要概念的定义如下:
|
|
|
|
|
|
|
|
|
|
- **对象(Object)**: 具备属性和行为的客体。客体之间可有各种联系。从简单的**整数**到复杂的**操作系统进程**等都可看做对象,它不仅仅表示具体的事物,还能表示抽象的规则、计划或事件。
|
|
|
|
|
- **句柄(Handle)**:标识对象的符号,也可看成是一种指向对象的变量(也可称为标识符、引用、ID等)。
|
|
|
|
|
- **权限(Rights)**:是指对象的访问者被允许在对象上执行的操作,即对象的访问权限。当对象访问者打开对象的句柄,该句柄具有对其对象的访问权限的某种组合。
|
|
|
|
|
|
|
|
|
|
对于Zircon与对象、句柄、权限的关系,可简单地表述为:
|
|
|
|
|
|
|
|
|
|
* Zircon是一个基于对象的内核,内核资源被抽象封装在不同的 **对象** 中。
|
|
|
|
|
* 用户程序通过 **句柄** 与内核交互。句柄是对某一对象的引用,并且附加了特定的 **权限**。
|
|
|
|
|
@ -105,7 +111,7 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
|
|
|
|
|
|
|
|
|
|
## 实现 KernelObject 接口
|
|
|
|
|
|
|
|
|
|
所有的内核对象有一系列共同的属性和方法,我们称这些方法为对象的公共**接口(Interface)**。
|
|
|
|
|
所有的内核对象有一系列共同的属性和方法,我们称对象的方法为对象的公共**接口(Interface)**。
|
|
|
|
|
同一种方法在不同类型的对象中可能会有不同的行为,在面向对象语言中我们称其为**多态(Polymorphism)**。
|
|
|
|
|
|
|
|
|
|
Rust 是一门部分面向对象的语言,我们通常用它的 trait 实现接口和多态。
|
|
|
|
|
@ -137,8 +143,8 @@ pub trait KernelObject: Send + Sync {
|
|
|
|
|
{{#include ../../code/ch01-01/src/object/object_v1.rs:dummy_def}}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
这里我们采用一种[**内部可变性**]的设计模式:将对象的所有可变的部分封装到一个内部对象 `DummyObjectInner` 中,并在原对象中用自旋锁 [`Mutex`] 把它包起来,剩下的其它字段都是不可变的。
|
|
|
|
|
`Mutex` 会用最简单的方式帮我们处理好并发访问问题:如果有其他人正在访问,我就在这里死等。
|
|
|
|
|
为了有效地支持操作系统中的并行和并发处理,我们这里采用了一种[**内部可变性**]的设计模式:将对象的所有可变的部分封装到一个内部对象 `DummyObjectInner` 中,并在原对象中用可保证互斥访问的自旋锁 [`Mutex`] 把它包起来,剩下的其它字段都是不可变的。
|
|
|
|
|
`Mutex` 会用最简单的方式帮我们处理好并发访问问题:如果有其他人正在访问,我就在这里忙等。
|
|
|
|
|
数据被 `Mutex` 包起来之后需要首先使用 [`lock()`] 拿到锁之后才能访问。此时并发访问已经安全,因此被包起来的结构自动具有了 `Send + Sync` 特性。
|
|
|
|
|
|
|
|
|
|
[`Mutex`]: https://docs.rs/spin/0.5.2/spin/struct.Mutex.html
|
|
|
|
|
@ -161,12 +167,14 @@ pub trait KernelObject: Send + Sync {
|
|
|
|
|
{{#include ../../code/ch01-01/src/object/object_v1.rs:dummy_new}}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
根据文档描述,每个内核对象都有唯一的 ID。为此我们需要实现一个全局的 ID 分配方法。这里采用的方法是用一个静态变量存放下一个待分配 ID 值,每次分配就原子地 +1。
|
|
|
|
|
根据文档描述,每个内核对象都有唯一的 ID。为此我们需要实现一个全局的 ID 分配方法。这里采用的方法是用一个静态变量存放下一个待分配 ID 值,每次分配就原子地 加`1`。
|
|
|
|
|
ID 类型使用 `u64`,保证了数值空间足够大,在有生之年都不用担心溢出问题。在 Zircon 中 ID 从 1024 开始分配,1024 以下保留作内核内部使用。
|
|
|
|
|
|
|
|
|
|
另外注意这里 `new` 函数返回类型不是 `Self` 而是 `Arc<Self>`,这是为了以后方便而做的统一约定。
|
|
|
|
|
另外注意这里 `new` 函数返回类型不是 `Self` 而是 `Arc<Self>`,这是的[ `Arc` ]为了以后方便并行处理而做的统一约定。
|
|
|
|
|
|
|
|
|
|
[ `Arc` ]: https://doc.rust-lang.org/std/sync/struct.Arc.html
|
|
|
|
|
|
|
|
|
|
最后我们为它实现 `KernelObject` 接口:
|
|
|
|
|
最后我们为它实现 `KernelObject` 的基本接口:
|
|
|
|
|
|
|
|
|
|
```rust,noplaypen
|
|
|
|
|
// src/object/object.rs
|
|
|
|
|
@ -245,7 +253,7 @@ fn downcast_v2<T: KernelObject>(object: Arc<dyn KernelObject>) -> Arc<T> {
|
|
|
|
|
|
|
|
|
|
(题外话:这个库原来是不支持 `no_std` 的,zCore 有这个需求,于是就顺便帮他实现了一把)
|
|
|
|
|
|
|
|
|
|
按照它文档的描述,我们要为自己的接口实现向下转换,只需以下修改:
|
|
|
|
|
按照[`downcast-rs`] 文档的描述,我们要为自己的接口实现向下转换,只需以下修改:
|
|
|
|
|
|
|
|
|
|
```rust,noplaypen
|
|
|
|
|
// src/object/mod.rs
|
|
|
|
|
|