From 3ce5e12629c3d4bf93e099388e9a159df5c3df87 Mon Sep 17 00:00:00 2001 From: DeathWish5 Date: Sat, 31 Jul 2021 16:53:49 +0800 Subject: [PATCH 1/3] =?UTF-8?q?ch1-3=20=E5=AE=8C=E6=88=90=20Channel=20?= =?UTF-8?q?=E5=9F=BA=E7=A1=80=E4=BB=A3=E7=A0=81=EF=BC=8C=E8=BF=98=E9=9C=80?= =?UTF-8?q?=E8=A6=81=E8=B0=83=E6=95=B4=E6=B3=A8=E9=87=8A=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- code/Cargo.toml | 1 + code/ch01-03/.gitignore | 2 + code/ch01-03/Cargo.toml | 13 ++ code/ch01-03/src/error.rs | 232 ++++++++++++++++++++++++++++++ code/ch01-03/src/ipc/channel.rs | 180 +++++++++++++++++++++++ code/ch01-03/src/ipc/mod.rs | 4 + code/ch01-03/src/lib.rs | 9 ++ code/ch01-03/src/object/handle.rs | 18 +++ code/ch01-03/src/object/mod.rs | 160 +++++++++++++++++++++ code/ch01-03/src/object/rights.rs | 35 +++++ code/ch01-03/src/task/mod.rs | 3 + code/ch01-03/src/task/process.rs | 77 ++++++++++ 12 files changed, 734 insertions(+) create mode 100644 code/ch01-03/.gitignore create mode 100644 code/ch01-03/Cargo.toml create mode 100644 code/ch01-03/src/error.rs create mode 100644 code/ch01-03/src/ipc/channel.rs create mode 100644 code/ch01-03/src/ipc/mod.rs create mode 100644 code/ch01-03/src/lib.rs create mode 100644 code/ch01-03/src/object/handle.rs create mode 100644 code/ch01-03/src/object/mod.rs create mode 100644 code/ch01-03/src/object/rights.rs create mode 100644 code/ch01-03/src/task/mod.rs create mode 100644 code/ch01-03/src/task/process.rs diff --git a/code/Cargo.toml b/code/Cargo.toml index a833cfc..ebda3b9 100644 --- a/code/Cargo.toml +++ b/code/Cargo.toml @@ -2,4 +2,5 @@ members = [ "ch01-01", "ch01-02", + "ch01-03", ] diff --git a/code/ch01-03/.gitignore b/code/ch01-03/.gitignore new file mode 100644 index 0000000..a9d37c5 --- /dev/null +++ b/code/ch01-03/.gitignore @@ -0,0 +1,2 @@ +target +Cargo.lock diff --git a/code/ch01-03/Cargo.toml b/code/ch01-03/Cargo.toml new file mode 100644 index 0000000..8dafcc5 --- /dev/null +++ b/code/ch01-03/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "ch01-03" +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 } +bitflags = "1.2" +buddy_system_allocator = "0.7" diff --git a/code/ch01-03/src/error.rs b/code/ch01-03/src/error.rs new file mode 100644 index 0000000..c6e1cbf --- /dev/null +++ b/code/ch01-03/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, Eq, PartialEq)] +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-03/src/ipc/channel.rs b/code/ch01-03/src/ipc/channel.rs new file mode 100644 index 0000000..83541ca --- /dev/null +++ b/code/ch01-03/src/ipc/channel.rs @@ -0,0 +1,180 @@ +use { + super::*, + crate::error::*, + crate::object::*, + alloc::collections::VecDeque, + alloc::sync::{Arc, Weak}, + alloc::vec::Vec, + core::convert::TryInto, + core::sync::atomic::{AtomicU32, Ordering}, + spin::Mutex, +}; + +pub struct Channel { + base: KObjectBase, + peer: Weak, + recv_queue: Mutex>, + next_txid: AtomicU32, +} + +type T = MessagePacket; +type TxID = u32; + +impl_kobject!(Channel + fn peer(&self) -> ZxResult> { + let peer = self.peer.upgrade().ok_or(ZxError::PEER_CLOSED)?; + Ok(peer) + } + fn related_koid(&self) -> KoID { + self.peer.upgrade().map(|p| p.id()).unwrap_or(0) + } +); + +impl Channel { + /// Create a channel and return a pair of its endpoints + #[allow(unsafe_code)] + pub fn create() -> (Arc, Arc) { + let mut channel0 = Arc::new(Channel { + base: KObjectBase::default(), + peer: Weak::default(), + recv_queue: Default::default(), + next_txid: AtomicU32::new(0x8000_0000), + }); + let channel1 = Arc::new(Channel { + base: KObjectBase::default(), + peer: Arc::downgrade(&channel0), + recv_queue: Default::default(), + next_txid: AtomicU32::new(0x8000_0000), + }); + // no other reference of `channel0` + unsafe { + Arc::get_mut_unchecked(&mut channel0).peer = Arc::downgrade(&channel1); + } + (channel0, channel1) + } + + /// Read a packet from the channel if check is ok, otherwise the msg will keep. + pub fn read(&self) -> ZxResult { + let mut recv_queue = self.recv_queue.lock(); + if let Some(msg) = recv_queue.front() { + let msg = recv_queue.pop_front().unwrap(); + return Ok(msg); + } + if self.peer_closed() { + Err(ZxError::PEER_CLOSED) + } else { + Err(ZxError::SHOULD_WAIT) + } + } + + /// Write a packet to the channel + pub fn write(&self, msg: T) -> ZxResult { + let peer = self.peer.upgrade().ok_or(ZxError::PEER_CLOSED)?; + peer.push_general(msg); + Ok(()) + } + + /// Push a message to general queue, called from peer. + fn push_general(&self, msg: T) { + let mut send_queue = self.recv_queue.lock(); + send_queue.push_back(msg); + } + + /// Generate a new transaction ID for `call`. + fn new_txid(&self) -> TxID { + self.next_txid.fetch_add(1, Ordering::SeqCst) + } + + /// Is peer channel closed? + fn peer_closed(&self) -> bool { + self.peer.strong_count() == 0 + } +} + +/// The message transferred in the channel. +/// See [Channel](struct.Channel.html) for details. +#[derive(Default)] +pub struct MessagePacket { + /// The transition id of the message packet + pub txid: TxID, + /// The data carried by the message packet + pub data: Vec, + /// See [Channel](struct.Channel.html) for details. + pub handles: Vec, +} + +#[cfg(test)] +mod tests { + use super::*; + use alloc::boxed::Box; + use core::sync::atomic::*; + use core::time::Duration; + + #[test] + fn test_basics() { + let (end0, end1) = Channel::create(); + assert!(Arc::ptr_eq( + &end0.peer().unwrap().downcast_arc().unwrap(), + &end1 + )); + assert_eq!(end0.related_koid(), end1.id()); + + drop(end1); + assert_eq!(end0.peer().unwrap_err(), ZxError::PEER_CLOSED); + assert_eq!(end0.related_koid(), 0); + } + + #[test] + fn read_write() { + let (channel0, channel1) = Channel::create(); + // write a message to each other + let txid0 = channel0.new_txid(); + channel0 + .write(MessagePacket { + txid: txid0, + data: Vec::from("hello 1"), + handles: Vec::new(), + }) + .unwrap(); + let txid1 = channel1.new_txid(); + channel1 + .write(MessagePacket { + txid: txid1, + data: Vec::from("hello 0"), + handles: Vec::new(), + }) + .unwrap(); + + // read message should success + let recv_msg = channel1.read().unwrap(); + assert_eq!(recv_msg.txid, txid0); + assert_eq!(recv_msg.data.as_slice(), b"hello 1"); + assert!(recv_msg.handles.is_empty()); + + let recv_msg = channel0.read().unwrap(); + assert_eq!(recv_msg.txid, txid1); + assert_eq!(recv_msg.data.as_slice(), b"hello 0"); + assert!(recv_msg.handles.is_empty()); + + // read more message should fail. + assert_eq!(channel0.read().err(), Some(ZxError::SHOULD_WAIT)); + assert_eq!(channel1.read().err(), Some(ZxError::SHOULD_WAIT)); + } + + #[test] + fn peer_closed() { + let (channel0, channel1) = Channel::create(); + // write a message from peer, then drop it + channel1.write(MessagePacket::default()).unwrap(); + drop(channel1); + // read the first message should success. + channel0.read().unwrap(); + // read more message should fail. + assert_eq!(channel0.read().err(), Some(ZxError::PEER_CLOSED)); + // write message should fail. + assert_eq!( + channel0.write(MessagePacket::default()), + Err(ZxError::PEER_CLOSED) + ); + } +} diff --git a/code/ch01-03/src/ipc/mod.rs b/code/ch01-03/src/ipc/mod.rs new file mode 100644 index 0000000..c2632d8 --- /dev/null +++ b/code/ch01-03/src/ipc/mod.rs @@ -0,0 +1,4 @@ +use super::*; + +mod channel; +pub use self::channel::*; diff --git a/code/ch01-03/src/lib.rs b/code/ch01-03/src/lib.rs new file mode 100644 index 0000000..988633d --- /dev/null +++ b/code/ch01-03/src/lib.rs @@ -0,0 +1,9 @@ +#![no_std] +#![feature(get_mut_unchecked)] + +extern crate alloc; + +mod error; +mod ipc; +mod object; +mod task; diff --git a/code/ch01-03/src/object/handle.rs b/code/ch01-03/src/object/handle.rs new file mode 100644 index 0000000..614cd70 --- /dev/null +++ b/code/ch01-03/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-03/src/object/mod.rs b/code/ch01-03/src/object/mod.rs new file mode 100644 index 0000000..6fb000e --- /dev/null +++ b/code/ch01-03/src/object/mod.rs @@ -0,0 +1,160 @@ +use crate::error::*; +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); + /// 尝试获取对象伙伴 + /// + /// 当前该对象必须是 `Channel` + fn peer(&self) -> ZxResult> { + Err(ZxError::NOT_SUPPORTED) + } + /// 尝试获取关联对象 id,否则返回 0 + /// + /// 当前该对象必须是 `Channel` + fn related_koid(&self) -> KoID { + 0 + } +} + +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-03/src/object/rights.rs b/code/ch01-03/src/object/rights.rs new file mode 100644 index 0000000..49c6842 --- /dev/null +++ b/code/ch01-03/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-03/src/task/mod.rs b/code/ch01-03/src/task/mod.rs new file mode 100644 index 0000000..6841e7d --- /dev/null +++ b/code/ch01-03/src/task/mod.rs @@ -0,0 +1,3 @@ +use super::*; + +mod process; diff --git a/code/ch01-03/src/task/process.rs b/code/ch01-03/src/task/process.rs new file mode 100644 index 0000000..80988f5 --- /dev/null +++ b/code/ch01-03/src/task/process.rs @@ -0,0 +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 +} From 3192d46768e54d33d956da1e132a82349e8a8abb Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Mon, 2 Aug 2021 09:34:51 +0800 Subject: [PATCH 2/3] add .gitignore, update deploy.yml --- .github/workflows/deploy.yml | 2 +- .gitignore | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 .gitignore diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 8b4a56e..e2928c0 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -7,7 +7,7 @@ on: jobs: deploy: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - name: Setup mdBook diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..485dee6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea From bf14ecaa9215b62cce26709ce4066de663595453 Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Mon, 2 Aug 2021 09:38:10 +0800 Subject: [PATCH 3/3] update .gitignore --- .gitignore | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/.gitignore b/.gitignore index 485dee6..e2b92bc 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,29 @@ +## Editor +*.swp +*.swo +Session.vim +.cproject .idea +*.iml +.vscode +.project +.favorites.json +.settings/ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + +## File system +.DS_Store +desktop.ini