From cebda3390cdc4fcb8e9e0e39070a4c45bd515b27 Mon Sep 17 00:00:00 2001 From: Runji Wang Date: Sat, 3 Apr 2021 23:16:11 +0800 Subject: [PATCH] =?UTF-8?q?ch01-02=EF=BC=9A=E6=B7=BB=E5=8A=A0=E8=BF=9B?= =?UTF-8?q?=E7=A8=8B=E5=AF=B9=E8=B1=A1=E5=8F=8A=E9=94=99=E8=AF=AF=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- code/ch01-02/src/error.rs | 232 +++++++++++++++++++++++++++++ code/ch01-02/src/lib.rs | 1 + code/ch01-02/src/task/mod.rs | 2 + code/ch01-02/src/task/process.rs | 76 ++++++++++ docs/src/ch01-02-process-object.md | 44 +++++- 5 files changed, 351 insertions(+), 4 deletions(-) create mode 100644 code/ch01-02/src/error.rs diff --git a/code/ch01-02/src/error.rs b/code/ch01-02/src/error.rs new file mode 100644 index 0000000..bf0c607 --- /dev/null +++ b/code/ch01-02/src/error.rs @@ -0,0 +1,232 @@ +// ANCHOR: result +/// +pub type ZxResult = Result; +// ANCHOR_END: result + +// ANCHOR: error_begin +/// Zircon statuses are signed 32 bit integers. The space of values is +/// divided as follows: +/// - The zero value is for the OK status. +/// - Negative values are defined by the system, in this file. +/// - Positive values are reserved for protocol-specific error values, +/// and will never be defined by the system. +#[allow(non_camel_case_types, dead_code)] +#[repr(i32)] +#[derive(Debug, Clone, Copy)] +pub enum ZxError { + OK = 0, + + // ======= Internal failures ======= + /// The system encountered an otherwise unspecified error + /// while performing the operation. + INTERNAL = -1, + + /// The operation is not implemented, supported, + /// or enabled. + NOT_SUPPORTED = -2, + // ANCHOR_END: error_begin + /// The system was not able to allocate some resource + /// needed for the operation. + NO_RESOURCES = -3, + + /// The system was not able to allocate memory needed + /// for the operation. + NO_MEMORY = -4, + + // -5 used to be ZX_ERR_CALL_FAILED. + /// The system call was interrupted, but should be + /// retried. This should not be seen outside of the VDSO. + INTERNAL_INTR_RETRY = -6, + + // ======= Parameter errors ======= + /// an argument is invalid, ex. null pointer + INVALID_ARGS = -10, + + /// A specified handle value does not refer to a handle. + BAD_HANDLE = -11, + + /// The subject of the operation is the wrong type to + /// perform the operation. + /// Example: Attempting a message_read on a thread handle. + WRONG_TYPE = -12, + + /// The specified syscall number is invalid. + BAD_SYSCALL = -13, + + /// An argument is outside the valid range for this + /// operation. + OUT_OF_RANGE = -14, + + /// A caller provided buffer is too small for + /// this operation. + BUFFER_TOO_SMALL = -15, + + // ======= Precondition or state errors ======= + /// operation failed because the current state of the + /// object does not allow it, or a precondition of the operation is + /// not satisfied + BAD_STATE = -20, + + /// The time limit for the operation elapsed before + /// the operation completed. + TIMED_OUT = -21, + + /// The operation cannot be performed currently but + /// potentially could succeed if the caller waits for a prerequisite + /// to be satisfied, for example waiting for a handle to be readable + /// or writable. + /// Example: Attempting to read from a channel that has no + /// messages waiting but has an open remote will return ZX_ERR_SHOULD_WAIT. + /// Attempting to read from a channel that has no messages waiting + /// and has a closed remote end will return ZX_ERR_PEER_CLOSED. + SHOULD_WAIT = -22, + + /// The in-progress operation (e.g. a wait) has been + /// canceled. + CANCELED = -23, + + /// The operation failed because the remote end of the + /// subject of the operation was closed. + PEER_CLOSED = -24, + + /// The requested entity is not found. + NOT_FOUND = -25, + + /// An object with the specified identifier + /// already exists. + /// Example: Attempting to create a file when a file already exists + /// with that name. + ALREADY_EXISTS = -26, + + /// The operation failed because the named entity + /// is already owned or controlled by another entity. The operation + /// could succeed later if the current owner releases the entity. + ALREADY_BOUND = -27, + + /// The subject of the operation is currently unable + /// to perform the operation. + /// Note: This is used when there's no direct way for the caller to + /// observe when the subject will be able to perform the operation + /// and should thus retry. + UNAVAILABLE = -28, + + // ======= Permission check errors ======= + /// The caller did not have permission to perform + /// the specified operation. + ACCESS_DENIED = -30, + + // ======= Input-output errors ======= + /// Otherwise unspecified error occurred during I/O. + IO = -40, + + /// The entity the I/O operation is being performed on + /// rejected the operation. + /// Example: an I2C device NAK'ing a transaction or a disk controller + /// rejecting an invalid command, or a stalled USB endpoint. + IO_REFUSED = -41, + + /// The data in the operation failed an integrity + /// check and is possibly corrupted. + /// Example: CRC or Parity error. + IO_DATA_INTEGRITY = -42, + + /// The data in the operation is currently unavailable + /// and may be permanently lost. + /// Example: A disk block is irrecoverably damaged. + IO_DATA_LOSS = -43, + + /// The device is no longer available (has been + /// unplugged from the system, powered down, or the driver has been + /// unloaded, + IO_NOT_PRESENT = -44, + + /// More data was received from the device than expected. + /// Example: a USB "babble" error due to a device sending more data than + /// the host queued to receive. + IO_OVERRUN = -45, + + /// An operation did not complete within the required timeframe. + /// Example: A USB isochronous transfer that failed to complete due to an overrun or underrun. + IO_MISSED_DEADLINE = -46, + + /// The data in the operation is invalid parameter or is out of range. + /// Example: A USB transfer that failed to complete with TRB Error + IO_INVALID = -47, + + // ======== Filesystem Errors ======== + /// Path name is too long. + BAD_PATH = -50, + + /// Object is not a directory or does not support + /// directory operations. + /// Example: Attempted to open a file as a directory or + /// attempted to do directory operations on a file. + NOT_DIR = -51, + + /// Object is not a regular file. + NOT_FILE = -52, + + /// This operation would cause a file to exceed a + /// filesystem-specific size limit + FILE_BIG = -53, + + /// Filesystem or device space is exhausted. + NO_SPACE = -54, + + /// Directory is not empty. + NOT_EMPTY = -55, + + // ======== Flow Control ======== + // These are not errors, as such, and will never be returned + // by a syscall or public API. They exist to allow callbacks + // to request changes in operation. + /// Do not call again. + /// Example: A notification callback will be called on every + /// event until it returns something other than ZX_OK. + /// This status allows differentiation between "stop due to + /// an error" and "stop because the work is done." + STOP = -60, + + /// Advance to the next item. + /// Example: A notification callback will use this response + /// to indicate it did not "consume" an item passed to it, + /// but by choice, not due to an error condition. + NEXT = -61, + + /// Ownership of the item has moved to an asynchronous worker. + /// + /// Unlike ZX_ERR_STOP, which implies that iteration on an object + /// should stop, and ZX_ERR_NEXT, which implies that iteration + /// should continue to the next item, ZX_ERR_ASYNC implies + /// that an asynchronous worker is responsible for continuing iteration. + /// + /// Example: A notification callback will be called on every + /// event, but one event needs to handle some work asynchronously + /// before it can continue. ZX_ERR_ASYNC implies the worker is + /// responsible for resuming iteration once its work has completed. + ASYNC = -62, + + // ======== Network-related errors ======== + /// Specified protocol is not + /// supported. + PROTOCOL_NOT_SUPPORTED = -70, + + /// Host is unreachable. + ADDRESS_UNREACHABLE = -71, + + /// Address is being used by someone else. + ADDRESS_IN_USE = -72, + + /// Socket is not connected. + NOT_CONNECTED = -73, + + /// Remote peer rejected the connection. + CONNECTION_REFUSED = -74, + + /// Connection was reset. + CONNECTION_RESET = -75, + // ANCHOR: error_end + /// Connection was aborted. + CONNECTION_ABORTED = -76, +} +// ANCHOR_END: error_end diff --git a/code/ch01-02/src/lib.rs b/code/ch01-02/src/lib.rs index 7cbb4d7..8b25285 100644 --- a/code/ch01-02/src/lib.rs +++ b/code/ch01-02/src/lib.rs @@ -2,5 +2,6 @@ extern crate alloc; +mod error; mod object; mod task; diff --git a/code/ch01-02/src/task/mod.rs b/code/ch01-02/src/task/mod.rs index 98d6e1f..6841e7d 100644 --- a/code/ch01-02/src/task/mod.rs +++ b/code/ch01-02/src/task/mod.rs @@ -1 +1,3 @@ +use super::*; + mod process; diff --git a/code/ch01-02/src/task/process.rs b/code/ch01-02/src/task/process.rs index 8b13789..80988f5 100644 --- a/code/ch01-02/src/task/process.rs +++ b/code/ch01-02/src/task/process.rs @@ -1 +1,77 @@ +use super::*; +use crate::error::*; +use crate::object::*; +use alloc::collections::BTreeMap; +use alloc::sync::Arc; +use spin::Mutex; +// ANCHOR: process +/// 进程对象 +pub struct Process { + base: KObjectBase, + inner: Mutex, +} + +impl_kobject!(Process); + +struct ProcessInner { + handles: BTreeMap, +} + +pub type HandleValue = u32; + +impl Process { + /// 创建一个新的进程对象 + pub fn new() -> Arc { + Arc::new(Process { + base: KObjectBase::default(), + inner: Mutex::new(ProcessInner { + handles: BTreeMap::default(), + }), + }) + } + // ANCHOR_END: process + + // ANCHOR: add_remove_handle + /// 添加一个新的对象句柄 + pub fn add_handle(&self, handle: Handle) -> HandleValue { + let mut inner = self.inner.lock(); + let value = (0 as HandleValue..) + .find(|idx| !inner.handles.contains_key(idx)) + .unwrap(); + inner.handles.insert(value, handle); + value + } + + /// 删除一个对象句柄 + pub fn remove_handle(&self, handle_value: HandleValue) { + self.inner.lock().handles.remove(&handle_value); + } + // ANCHOR_END: add_remove_handle + + // ANCHOR: get_object_with_rights + /// 根据句柄值查找内核对象,并检查权限 + pub fn get_object_with_rights( + &self, + handle_value: HandleValue, + desired_rights: Rights, + ) -> ZxResult> { + let handle = self + .inner + .lock() + .handles + .get(&handle_value) + .ok_or(ZxError::BAD_HANDLE)? + .clone(); + // check type before rights + let object = handle + .object + .downcast_arc::() + .map_err(|_| ZxError::WRONG_TYPE)?; + if !handle.rights.contains(desired_rights) { + return Err(ZxError::ACCESS_DENIED); + } + Ok(object) + } + // ANCHOR_END: get_object_with_rights +} diff --git a/docs/src/ch01-02-process-object.md b/docs/src/ch01-02-process-object.md index b523d40..e4c7925 100644 --- a/docs/src/ch01-02-process-object.md +++ b/docs/src/ch01-02-process-object.md @@ -35,18 +35,54 @@ {{#include ../../code/ch01-02/src/object/handle.rs:handle}} ``` -## 实现第一个内核对象 - -> 使用上一节的方法,实现一个空的 Process 对象 - ## 存储内核对象句柄 > 添加成员变量 handles: BTreeMap > > 实现 create,add_handle,remove_handle 函数 +使用上一节的方法,实现一个空的 Process 对象: + +```rust,noplaypen +// src/task/process.rs +{{#include ../../code/ch01-02/src/task/process.rs:process}} +} +``` + +插入、删除句柄函数: + +```rust,noplaypen +// src/task/process.rs +impl Process { +{{#include ../../code/ch01-02/src/task/process.rs:add_remove_handle}} +} +``` + +## 定义内核错误及 `Result` 类型 + +```rust,noplaypen +// src/error.rs +{{#include ../../code/ch01-02/src/error.rs:error_begin}} + + // ...... + +{{#include ../../code/ch01-02/src/error.rs:error_end}} +``` + +```rust,noplaypen +// src/error.rs +{{#include ../../code/ch01-02/src/error.rs:result}} +``` + ## 根据句柄查找内核对象 > 实现 get_object_with_rights 等其它相关函数 > > 实现 handle 单元测试 + +```rust,noplaypen +// src/task/process.rs +impl Process { +{{#include ../../code/ch01-02/src/task/process.rs:get_object_with_rights}} +} +```