From 599e4a82096326f18961ec0466d5233114bdaa62 Mon Sep 17 00:00:00 2001 From: Runji Wang Date: Sat, 3 Apr 2021 22:37:24 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=9D=83=E9=99=90=E5=92=8C?= =?UTF-8?q?=E5=8F=A5=E6=9F=84=E7=9A=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- code/Cargo.toml | 1 + code/ch01-02/.gitignore | 2 + code/ch01-02/Cargo.toml | 14 +++ code/ch01-02/src/lib.rs | 6 ++ code/ch01-02/src/object/handle.rs | 18 ++++ code/ch01-02/src/object/mod.rs | 147 +++++++++++++++++++++++++++++ code/ch01-02/src/object/rights.rs | 35 +++++++ code/ch01-02/src/task/mod.rs | 1 + code/ch01-02/src/task/process.rs | 1 + docs/src/ch01-02-process-object.md | 28 ++++++ 10 files changed, 253 insertions(+) create mode 100644 code/ch01-02/.gitignore create mode 100644 code/ch01-02/Cargo.toml create mode 100644 code/ch01-02/src/lib.rs create mode 100644 code/ch01-02/src/object/handle.rs create mode 100644 code/ch01-02/src/object/mod.rs create mode 100644 code/ch01-02/src/object/rights.rs create mode 100644 code/ch01-02/src/task/mod.rs create mode 100644 code/ch01-02/src/task/process.rs diff --git a/code/Cargo.toml b/code/Cargo.toml index cdb9b9f..a833cfc 100644 --- a/code/Cargo.toml +++ b/code/Cargo.toml @@ -1,4 +1,5 @@ [workspace] members = [ "ch01-01", + "ch01-02", ] diff --git a/code/ch01-02/.gitignore b/code/ch01-02/.gitignore new file mode 100644 index 0000000..a9d37c5 --- /dev/null +++ b/code/ch01-02/.gitignore @@ -0,0 +1,2 @@ +target +Cargo.lock diff --git a/code/ch01-02/Cargo.toml b/code/ch01-02/Cargo.toml new file mode 100644 index 0000000..bae08bf --- /dev/null +++ b/code/ch01-02/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "ch01-02" +version = "0.1.0" +authors = ["Runji Wang "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +spin = "0.7" +downcast-rs = { version = "1.2.0", default-features = false } +# ANCHOR: bitflags +bitflags = "1.2" +# ANCHOR_END: bitflags diff --git a/code/ch01-02/src/lib.rs b/code/ch01-02/src/lib.rs new file mode 100644 index 0000000..7cbb4d7 --- /dev/null +++ b/code/ch01-02/src/lib.rs @@ -0,0 +1,6 @@ +#![no_std] + +extern crate alloc; + +mod object; +mod task; diff --git a/code/ch01-02/src/object/handle.rs b/code/ch01-02/src/object/handle.rs new file mode 100644 index 0000000..614cd70 --- /dev/null +++ b/code/ch01-02/src/object/handle.rs @@ -0,0 +1,18 @@ +// ANCHOR: handle +use super::{KernelObject, Rights}; +use alloc::sync::Arc; + +/// 内核对象句柄 +#[derive(Clone)] +pub struct Handle { + pub object: Arc, + pub rights: Rights, +} + +impl Handle { + /// 创建一个新句柄 + pub fn new(object: Arc, rights: Rights) -> Self { + Handle { object, rights } + } +} +// ANCHOR_END: handle diff --git a/code/ch01-02/src/object/mod.rs b/code/ch01-02/src/object/mod.rs new file mode 100644 index 0000000..b861062 --- /dev/null +++ b/code/ch01-02/src/object/mod.rs @@ -0,0 +1,147 @@ +use alloc::string::String; +use alloc::sync::Arc; +use core::fmt::Debug; +use core::sync::atomic::*; +use downcast_rs::{impl_downcast, DowncastSync}; +use spin::Mutex; + +// ANCHOR: mod +mod handle; +mod rights; + +pub use self::handle::*; +pub use self::rights::*; +// ANCHOR_END: mod + +/// 内核对象公共接口 +pub trait KernelObject: DowncastSync + Debug { + /// 获取对象 ID + fn id(&self) -> KoID; + /// 获取对象类型名 + fn type_name(&self) -> &str; + /// 获取对象名称 + fn name(&self) -> String; + /// 设置对象名称 + fn set_name(&self, name: &str); +} + +impl_downcast!(sync KernelObject); + +/// 对象 ID 类型 +pub type KoID = u64; + +/// 内核对象核心结构 +pub struct KObjectBase { + /// 对象 ID + pub id: KoID, + inner: Mutex, +} + +/// `KObjectBase` 的内部可变部分 +#[derive(Default)] +struct KObjectBaseInner { + name: String, +} + +impl Default for KObjectBase { + /// 创建一个新 `KObjectBase` + fn default() -> Self { + KObjectBase { + id: Self::new_koid(), + inner: Default::default(), + } + } +} + +impl KObjectBase { + /// 生成一个唯一的 ID + fn new_koid() -> KoID { + static NEXT_KOID: AtomicU64 = AtomicU64::new(1024); + NEXT_KOID.fetch_add(1, Ordering::SeqCst) + } + /// 获取对象名称 + pub fn name(&self) -> String { + self.inner.lock().name.clone() + } + /// 设置对象名称 + pub fn set_name(&self, name: &str) { + self.inner.lock().name = String::from(name); + } +} + +/// 为内核对象 struct 自动实现 `KernelObject` trait 的宏。 +#[macro_export] // 导出宏,可在 crate 外部使用 +macro_rules! impl_kobject { + // 匹配类型名,并可以提供函数覆盖默认实现 + ($class:ident $( $fn:tt )*) => { + // 为对象实现 KernelObject trait,方法直接转发到内部 struct + impl KernelObject for $class { + fn id(&self) -> KoID { + // 直接访问内部的 pub 属性 + self.base.id + } + fn type_name(&self) -> &str { + // 用 stringify! 宏将输入转成字符串 + stringify!($class) + } + // 注意宏里面的类型要写完整路径,例如:alloc::string::String + fn name(&self) -> alloc::string::String { + self.base.name() + } + fn set_name(&self, name: &str){ + // 直接访问内部的 pub 方法 + self.base.set_name(name) + } + // 可以传入任意数量的函数,覆盖 trait 的默认实现 + $( $fn )* + } + // 为对象实现 Debug trait + impl core::fmt::Debug for $class { + fn fmt( + &self, + f: &mut core::fmt::Formatter<'_>, + ) -> core::result::Result<(), core::fmt::Error> { + // 输出对象类型、ID 和名称 + f.debug_tuple(&stringify!($class)) + .field(&self.id()) + .field(&self.name()) + .finish() + } + } + }; +} + +/// 空对象 +pub struct DummyObject { + // 其中必须包含一个名为 `base` 的 `KObjectBase` + base: KObjectBase, +} + +// 使用刚才的宏,声明其为内核对象,自动生成必要的代码 +impl_kobject!(DummyObject); + +impl DummyObject { + /// 创建一个新 `DummyObject` + pub fn new() -> Arc { + Arc::new(DummyObject { + base: KObjectBase::default(), + }) + } +} + +#[cfg(test)] +#[test] +fn impl_kobject() { + use alloc::format; + let dummy = DummyObject::new(); + let object: Arc = dummy; + assert_eq!(object.type_name(), "DummyObject"); + assert_eq!(object.name(), ""); + object.set_name("dummy"); + assert_eq!(object.name(), "dummy"); + assert_eq!( + format!("{:?}", object), + format!("DummyObject({}, \"dummy\")", object.id()) + ); + let _result: Arc = object.downcast_arc::().unwrap(); +} diff --git a/code/ch01-02/src/object/rights.rs b/code/ch01-02/src/object/rights.rs new file mode 100644 index 0000000..49c6842 --- /dev/null +++ b/code/ch01-02/src/object/rights.rs @@ -0,0 +1,35 @@ +// ANCHOR: rights +use bitflags::bitflags; + +bitflags! { + /// 句柄权限 + pub struct Rights: u32 { + const DUPLICATE = 1 << 0; + const TRANSFER = 1 << 1; + const READ = 1 << 2; + const WRITE = 1 << 3; + const EXECUTE = 1 << 4; + const MAP = 1 << 5; + const GET_PROPERTY = 1 << 6; + const SET_PROPERTY = 1 << 7; + const ENUMERATE = 1 << 8; + const DESTROY = 1 << 9; + const SET_POLICY = 1 << 10; + const GET_POLICY = 1 << 11; + const SIGNAL = 1 << 12; + const SIGNAL_PEER = 1 << 13; + const WAIT = 1 << 14; + const INSPECT = 1 << 15; + const MANAGE_JOB = 1 << 16; + const MANAGE_PROCESS = 1 << 17; + const MANAGE_THREAD = 1 << 18; + const APPLY_PROFILE = 1 << 19; + const SAME_RIGHTS = 1 << 31; + + const BASIC = Self::TRANSFER.bits | Self::DUPLICATE.bits | Self::WAIT.bits | Self::INSPECT.bits; + const IO = Self::READ.bits | Self::WRITE.bits; + + const DEFAULT_CHANNEL = Self::BASIC.bits & !Self::DUPLICATE.bits | Self::IO.bits | Self::SIGNAL.bits | Self::SIGNAL_PEER.bits; + } +} +// ANCHOR_END: rights diff --git a/code/ch01-02/src/task/mod.rs b/code/ch01-02/src/task/mod.rs new file mode 100644 index 0000000..98d6e1f --- /dev/null +++ b/code/ch01-02/src/task/mod.rs @@ -0,0 +1 @@ +mod process; diff --git a/code/ch01-02/src/task/process.rs b/code/ch01-02/src/task/process.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/code/ch01-02/src/task/process.rs @@ -0,0 +1 @@ + diff --git a/docs/src/ch01-02-process-object.md b/docs/src/ch01-02-process-object.md index 8e633cd..b523d40 100644 --- a/docs/src/ch01-02-process-object.md +++ b/docs/src/ch01-02-process-object.md @@ -7,6 +7,34 @@ > 介绍并实现 Handle,Rights +在 `Cargo.toml` 中加入 `bitflags` 库: + +```rust,noplaypen +[dependencies] +{{#include ../../code/ch01-02/Cargo.toml:bitflags}} +``` + +在 object 模块下定义两个子模块: + +```rust,noplaypen +// src/object/mod.rs +{{#include ../../code/ch01-02/src/object/mod.rs:mod}} +``` + +定义权限: + +```rust,noplaypen +// src/object/rights.rs +{{#include ../../code/ch01-02/src/object/rights.rs:rights}} +``` + +定义句柄: + +```rust,noplaypen +// src/object/handle.rs +{{#include ../../code/ch01-02/src/object/handle.rs:handle}} +``` + ## 实现第一个内核对象 > 使用上一节的方法,实现一个空的 Process 对象