From fe4ee39b03a41a11828b432430cd45bbf20e1dea Mon Sep 17 00:00:00 2001 From: DeathWish5 Date: Wed, 4 Aug 2021 18:27:49 +0800 Subject: [PATCH] ch02-02, basic code --- code/Cargo.toml | 1 + code/ch01-03/Cargo.toml | 1 - code/ch02-02/Cargo.toml | 4 +- code/ch02-02/src/ipc/channel.rs | 6 +- code/ch02-02/src/lib.rs | 9 + code/ch02-02/src/object/handle.rs | 2 + code/ch02-02/src/object/mod.rs | 19 +- code/ch02-02/src/object/rights.rs | 22 ++ code/ch02-02/src/task/job.rs | 61 +--- code/ch02-02/src/task/job_policy.rs | 44 --- code/ch02-02/src/task/mod.rs | 9 +- code/ch02-02/src/task/process.rs | 456 +++++++++++++++++++++++++--- code/ch02-02/src/task/thread.rs | 24 ++ code/ch02-02/src/vm/mod.rs | 6 + code/ch02-02/src/vm/vmar.rs | 17 ++ 15 files changed, 524 insertions(+), 157 deletions(-) create mode 100644 code/ch02-02/src/task/thread.rs create mode 100644 code/ch02-02/src/vm/mod.rs create mode 100644 code/ch02-02/src/vm/vmar.rs diff --git a/code/Cargo.toml b/code/Cargo.toml index ebda3b9..20ef163 100644 --- a/code/Cargo.toml +++ b/code/Cargo.toml @@ -3,4 +3,5 @@ members = [ "ch01-01", "ch01-02", "ch01-03", + "ch02-02", ] diff --git a/code/ch01-03/Cargo.toml b/code/ch01-03/Cargo.toml index 8dafcc5..e8fbd26 100644 --- a/code/ch01-03/Cargo.toml +++ b/code/ch01-03/Cargo.toml @@ -10,4 +10,3 @@ edition = "2018" spin = "0.7" downcast-rs = { version = "1.2.0", default-features = false } bitflags = "1.2" -buddy_system_allocator = "0.7" diff --git a/code/ch02-02/Cargo.toml b/code/ch02-02/Cargo.toml index 8dafcc5..b611f44 100644 --- a/code/ch02-02/Cargo.toml +++ b/code/ch02-02/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "ch01-03" +name = "ch02-02" version = "0.1.0" authors = ["Runji Wang "] edition = "2018" @@ -10,4 +10,4 @@ edition = "2018" spin = "0.7" downcast-rs = { version = "1.2.0", default-features = false } bitflags = "1.2" -buddy_system_allocator = "0.7" +hashbrown = "0.9" \ No newline at end of file diff --git a/code/ch02-02/src/ipc/channel.rs b/code/ch02-02/src/ipc/channel.rs index 83541ca..f8f7d59 100644 --- a/code/ch02-02/src/ipc/channel.rs +++ b/code/ch02-02/src/ipc/channel.rs @@ -5,7 +5,6 @@ use { alloc::collections::VecDeque, alloc::sync::{Arc, Weak}, alloc::vec::Vec, - core::convert::TryInto, core::sync::atomic::{AtomicU32, Ordering}, spin::Mutex, }; @@ -56,7 +55,7 @@ impl Channel { /// 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() { + if let Some(_) = recv_queue.front() { let msg = recv_queue.pop_front().unwrap(); return Ok(msg); } @@ -106,9 +105,6 @@ pub struct MessagePacket { #[cfg(test)] mod tests { use super::*; - use alloc::boxed::Box; - use core::sync::atomic::*; - use core::time::Duration; #[test] fn test_basics() { diff --git a/code/ch02-02/src/lib.rs b/code/ch02-02/src/lib.rs index 988633d..306d8b9 100644 --- a/code/ch02-02/src/lib.rs +++ b/code/ch02-02/src/lib.rs @@ -1,9 +1,18 @@ #![no_std] +#![deny(unused_imports)] +#![allow(dead_code)] #![feature(get_mut_unchecked)] extern crate alloc; +#[cfg(test)] +#[macro_use] +extern crate std; + mod error; mod ipc; mod object; mod task; +mod vm; + +pub use self::error::*; diff --git a/code/ch02-02/src/object/handle.rs b/code/ch02-02/src/object/handle.rs index 614cd70..3b50df2 100644 --- a/code/ch02-02/src/object/handle.rs +++ b/code/ch02-02/src/object/handle.rs @@ -2,6 +2,8 @@ use super::{KernelObject, Rights}; use alloc::sync::Arc; +pub type HandleValue = u32; + /// 内核对象句柄 #[derive(Clone)] pub struct Handle { diff --git a/code/ch02-02/src/object/mod.rs b/code/ch02-02/src/object/mod.rs index 9d1ef8d..487bdf5 100644 --- a/code/ch02-02/src/object/mod.rs +++ b/code/ch02-02/src/object/mod.rs @@ -1,4 +1,3 @@ -use crate::error::*; use alloc::string::String; use alloc::sync::Arc; use core::fmt::Debug; @@ -6,13 +5,12 @@ 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 use super::*; /// 内核对象公共接口 pub trait KernelObject: DowncastSync + Debug { @@ -79,6 +77,11 @@ impl Default for KObjectBase { } impl KObjectBase { + /// Create a new kernel object base. + pub fn new() -> Self { + Self::default() + } + /// 生成一个唯一的 ID fn new_koid() -> KoID { static NEXT_KOID: AtomicU64 = AtomicU64::new(1024); @@ -92,6 +95,16 @@ impl KObjectBase { pub fn set_name(&self, name: &str) { self.inner.lock().name = String::from(name); } + + /// Create a kernel object base with `name`. + pub fn with_name(name: &str) -> Self { + KObjectBase { + id: Self::new_koid(), + inner: Mutex::new(KObjectBaseInner { + name: String::from(name), + }), + } + } } /// 为内核对象 struct 自动实现 `KernelObject` trait 的宏。 diff --git a/code/ch02-02/src/object/rights.rs b/code/ch02-02/src/object/rights.rs index 49c6842..c69dcaf 100644 --- a/code/ch02-02/src/object/rights.rs +++ b/code/ch02-02/src/object/rights.rs @@ -29,7 +29,29 @@ bitflags! { const BASIC = Self::TRANSFER.bits | Self::DUPLICATE.bits | Self::WAIT.bits | Self::INSPECT.bits; const IO = Self::READ.bits | Self::WRITE.bits; + /// GET_PROPERTY | SET_PROPERTY + const PROPERTY = Self::GET_PROPERTY.bits | Self::SET_PROPERTY.bits; + + /// GET_POLICY | SET_POLICY + const POLICY = Self::GET_POLICY.bits | Self::SET_POLICY.bits; + + /// BASIC & !Self::DUPLICATE | IO | SIGNAL | SIGNAL_PEER const DEFAULT_CHANNEL = Self::BASIC.bits & !Self::DUPLICATE.bits | Self::IO.bits | Self::SIGNAL.bits | Self::SIGNAL_PEER.bits; + + /// BASIC | IO | PROPERTY | ENUMERATE | DESTROY | SIGNAL | MANAGE_PROCESS | MANAGE_THREAD + const DEFAULT_PROCESS = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::ENUMERATE.bits | Self::DESTROY.bits + | Self::SIGNAL.bits | Self::MANAGE_PROCESS.bits | Self::MANAGE_THREAD.bits; + + /// BASIC | IO | PROPERTY | DESTROY | SIGNAL | MANAGE_THREAD + const DEFAULT_THREAD = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::DESTROY.bits | Self::SIGNAL.bits | Self::MANAGE_THREAD.bits; + + /// BASIC | WAIT + const DEFAULT_VMAR = Self::BASIC.bits & !Self::WAIT.bits; + + /// BASIC | IO | PROPERTY | POLICY | ENUMERATE | DESTROY | SIGNAL | MANAGE_JOB | MANAGE_PROCESS | MANAGE_THREAD + const DEFAULT_JOB = Self::BASIC.bits | Self::IO.bits | Self::PROPERTY.bits | Self::POLICY.bits | Self::ENUMERATE.bits + | Self::DESTROY.bits | Self::SIGNAL.bits | Self::MANAGE_JOB.bits | Self::MANAGE_PROCESS.bits | Self::MANAGE_THREAD.bits; + } } // ANCHOR_END: rights diff --git a/code/ch02-02/src/task/job.rs b/code/ch02-02/src/task/job.rs index ad46085..d2f1b34 100644 --- a/code/ch02-02/src/task/job.rs +++ b/code/ch02-02/src/task/job.rs @@ -1,6 +1,8 @@ use { super::job_policy::*, super::process::Process, + super::*, + crate::error::*, crate::object::*, crate::task::Task, alloc::sync::{Arc, Weak}, @@ -122,17 +124,6 @@ impl Job { Ok(()) } - /// Sets timer slack policy to an empty job. - pub fn set_policy_timer_slack(&self, policy: TimerSlackPolicy) -> ZxResult { - let mut inner = self.inner.lock(); - if !inner.is_empty() { - return Err(ZxError::BAD_STATE); - } - check_timer_policy(&policy)?; - inner.timer_policy = inner.timer_policy.generate_new(policy); - Ok(()) - } - /// Add a process to the job. pub(super) fn add_process(&self, process: Arc) -> ZxResult { let mut inner = self.inner.lock(); @@ -241,7 +232,7 @@ impl Drop for Job { #[cfg(test)] mod tests { use super::*; - use crate::task::{CurrentThread, Status, Thread, ThreadState, TASK_RETCODE_SYSCALL_KILL}; + use crate::task::TASK_RETCODE_SYSCALL_KILL; #[test] fn create() { @@ -387,35 +378,23 @@ mod tests { let job = Job::create_child(&root_job).expect("failed to create job"); let proc = Process::create(&root_job, "proc").expect("failed to create process"); let thread = Thread::create(&proc, "thread").expect("failed to create thread"); - let current_thread = CurrentThread(thread.clone()); root_job.kill(); assert!(root_job.inner.lock().killed); assert!(job.inner.lock().killed); assert_eq!(proc.status(), Status::Exited(TASK_RETCODE_SYSCALL_KILL)); - assert_eq!(thread.state(), ThreadState::Dying); - // killed but not terminated, since `CurrentThread` not dropped. - assert!(!root_job.signal().contains(Signal::JOB_TERMINATED)); - assert!(job.signal().contains(Signal::JOB_TERMINATED)); // but the lonely job is terminated - assert!(!proc.signal().contains(Signal::PROCESS_TERMINATED)); - assert!(!thread.signal().contains(Signal::THREAD_TERMINATED)); - - std::mem::drop(current_thread); + // assert_eq!(thread.state(), ThreadState::Dying); + + std::mem::drop(thread); assert!(root_job.inner.lock().killed); assert!(job.inner.lock().killed); assert_eq!(proc.status(), Status::Exited(TASK_RETCODE_SYSCALL_KILL)); - assert_eq!(thread.state(), ThreadState::Dead); - // all terminated now - assert!(root_job.signal().contains(Signal::JOB_TERMINATED)); - assert!(job.signal().contains(Signal::JOB_TERMINATED)); - assert!(proc.signal().contains(Signal::PROCESS_TERMINATED)); - assert!(thread.signal().contains(Signal::THREAD_TERMINATED)); + // assert_eq!(thread.state(), ThreadState::Dead); // The job has no children. let root_job = Job::root(); root_job.kill(); assert!(root_job.inner.lock().killed); - assert!(root_job.signal().contains(Signal::JOB_TERMINATED)); // The job's process have no threads. let root_job = Job::root(); @@ -425,31 +404,5 @@ mod tests { assert!(root_job.inner.lock().killed); assert!(job.inner.lock().killed); assert_eq!(proc.status(), Status::Exited(TASK_RETCODE_SYSCALL_KILL)); - assert!(root_job.signal().contains(Signal::JOB_TERMINATED)); - assert!(job.signal().contains(Signal::JOB_TERMINATED)); - assert!(proc.signal().contains(Signal::PROCESS_TERMINATED)); - } - - #[test] - fn critical_process() { - let root_job = Job::root(); - let job = root_job.create_child().unwrap(); - let job1 = root_job.create_child().unwrap(); - - let proc = Process::create(&job, "proc").expect("failed to create process"); - - assert_eq!( - proc.set_critical_at_job(&job1, true).err(), - Some(ZxError::INVALID_ARGS) - ); - proc.set_critical_at_job(&root_job, true).unwrap(); - assert_eq!( - proc.set_critical_at_job(&job, true).err(), - Some(ZxError::ALREADY_BOUND) - ); - - proc.exit(666); - assert!(root_job.inner.lock().killed); - assert!(root_job.signal().contains(Signal::JOB_TERMINATED)); } } diff --git a/code/ch02-02/src/task/job_policy.rs b/code/ch02-02/src/task/job_policy.rs index 6016c45..d7ff32d 100644 --- a/code/ch02-02/src/task/job_policy.rs +++ b/code/ch02-02/src/task/job_policy.rs @@ -1,5 +1,3 @@ -use crate::error::*; - /// Security and resource policies of a job. #[derive(Default, Copy, Clone)] pub struct JobPolicy { @@ -108,45 +106,3 @@ pub enum PolicyAction { /// Terminate the process. Kill = 4, } - -/// Timer slack policy. -/// -/// See [timer slack](../../signal/timer/enum.Slack.html) for more information. -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct TimerSlackPolicy { - min_slack: i64, - default_mode: Slack, -} - -/// Check whether the policy is valid. -pub fn check_timer_policy(policy: &TimerSlackPolicy) -> ZxResult { - if policy.min_slack.is_negative() { - return Err(ZxError::INVALID_ARGS); - } - Ok(()) -} - -#[repr(C)] -pub(super) struct TimerSlack { - amount: i64, - mode: Slack, -} - -impl TimerSlack { - pub(super) fn generate_new(&self, policy: TimerSlackPolicy) -> TimerSlack { - TimerSlack { - amount: self.amount.max(policy.min_slack), - mode: policy.default_mode, - } - } -} - -impl Default for TimerSlack { - fn default() -> Self { - TimerSlack { - amount: 0, - mode: Slack::Center, - } - } -} diff --git a/code/ch02-02/src/task/mod.rs b/code/ch02-02/src/task/mod.rs index d5765af..afa11d3 100644 --- a/code/ch02-02/src/task/mod.rs +++ b/code/ch02-02/src/task/mod.rs @@ -3,6 +3,9 @@ use super::*; mod job; mod job_policy; mod process; +mod thread; + +pub use {self::job::*, self::job_policy::*, self::process::*, self::thread::*}; /// Task (Thread, Process, or Job) pub trait Task: Sync + Send { @@ -15,12 +18,6 @@ pub trait Task: Sync + Send { /// Resume the task fn resume(&self); - - /// Get the exceptionate. - fn exceptionate(&self) -> Arc; - - /// Get the debug exceptionate. - fn debug_exceptionate(&self) -> Arc; } /// The return code set when a task is killed via zx_task_kill(). diff --git a/code/ch02-02/src/task/process.rs b/code/ch02-02/src/task/process.rs index 80988f5..98d896e 100644 --- a/code/ch02-02/src/task/process.rs +++ b/code/ch02-02/src/task/process.rs @@ -1,68 +1,116 @@ -use super::*; -use crate::error::*; -use crate::object::*; -use alloc::collections::BTreeMap; -use alloc::sync::Arc; -use spin::Mutex; - -// ANCHOR: process -/// 进程对象 +use { + super::{job::Job, job_policy::*, thread::*, *}, + crate::{error::*, object::*, vm::*}, + alloc::{sync::Arc, vec::Vec}, + hashbrown::HashMap, + spin::Mutex, +}; + pub struct Process { base: KObjectBase, + job: Arc, + policy: JobPolicy, + vmar: Arc, inner: Mutex, } -impl_kobject!(Process); +impl_kobject!(Process + fn get_child(&self, id: KoID) -> ZxResult> { + let inner = self.inner.lock(); + let thread = inner.threads.iter().find(|o| o.id() == id).ok_or(ZxError::NOT_FOUND)?; + Ok(thread.clone()) + } + fn related_koid(&self) -> KoID { + self.job.id() + } +); +#[derive(Default)] struct ProcessInner { - handles: BTreeMap, + max_handle_id: u32, + status: Status, + handles: HashMap, + threads: Vec>, +} + +/// Status of a process. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum Status { + /// Initial state, no thread present in process. + Init, + /// First thread has started and is running. + Running, + /// Process has exited with the code. + Exited(i64), } -pub type HandleValue = u32; +impl Default for Status { + fn default() -> Self { + Status::Init + } +} 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 + /// Create a new process in the `job`. + pub fn create(job: &Arc, name: &str) -> ZxResult> { + let proc = Arc::new(Process { + base: KObjectBase::with_name(name), + job: job.clone(), + policy: job.policy(), + vmar: VmAddressRegion::new_root(), + inner: Mutex::new(ProcessInner::default()), + }); + job.add_process(proc.clone())?; + Ok(proc) + } + + /// Get a handle from the process + fn get_handle(&self, handle_value: HandleValue) -> ZxResult { + self.inner.lock().get_handle(handle_value) + } + /// 添加一个新的对象句柄 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 + self.inner.lock().add_handle(handle) } /// 删除一个对象句柄 - pub fn remove_handle(&self, handle_value: HandleValue) { - self.inner.lock().handles.remove(&handle_value); + pub fn remove_handle(&self, handle_value: HandleValue) -> ZxResult { + self.inner.lock().remove_handle(handle_value) + } + + /// Add all handles to the process + pub fn add_handles(&self, handles: Vec) -> Vec { + let mut inner = self.inner.lock(); + handles.into_iter().map(|h| inner.add_handle(h)).collect() + } + + /// Remove all handles from the process. + pub fn remove_handles(&self, handle_values: &[HandleValue]) -> ZxResult> { + let mut inner = self.inner.lock(); + handle_values + .iter() + .map(|h| inner.remove_handle(*h)) + .collect() + } + + /// Get the kernel object corresponding to this `handle_value` + pub fn get_object(&self, handle_value: HandleValue) -> ZxResult> { + let handle = self.get_handle(handle_value)?; + let object = handle + .object + .downcast_arc::() + .map_err(|_| ZxError::WRONG_TYPE)?; + Ok(object) } - // 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(); + let handle = self.get_handle(handle_value)?; // check type before rights let object = handle .object @@ -73,5 +121,329 @@ impl Process { } Ok(object) } - // ANCHOR_END: get_object_with_rights + + /// Get the kernel object corresponding to this `handle_value` and this handle's rights. + pub fn get_object_and_rights( + &self, + handle_value: HandleValue, + ) -> ZxResult<(Arc, Rights)> { + let handle = self.get_handle(handle_value)?; + let object = handle + .object + .downcast_arc::() + .map_err(|_| ZxError::WRONG_TYPE)?; + Ok((object, handle.rights)) + } + + /// Remove a handle referring to a kernel object of the given type from the process. + pub fn remove_object(&self, handle_value: HandleValue) -> ZxResult> { + let handle = self.remove_handle(handle_value)?; + let object = handle + .object + .downcast_arc::() + .map_err(|_| ZxError::WRONG_TYPE)?; + Ok(object) + } + + pub fn start(&self) -> () { + // unimplemented!() + } + + /// Exit current process with `retcode`. + /// The process do not terminate immediately when exited. + /// It will terminate after all its child threads are terminated. + pub fn exit(&self, retcode: i64) { + let mut inner = self.inner.lock(); + if let Status::Exited(_) = inner.status { + return; + } + inner.status = Status::Exited(retcode); + inner.handles.clear(); + } + + /// The process finally terminates. + fn terminate(&self) { + // unimplemented!() + } + + /// Check whether `condition` is allowed in the parent job's policy. + pub fn check_policy(&self, condition: PolicyCondition) -> ZxResult { + match self + .policy + .get_action(condition) + .unwrap_or(PolicyAction::Allow) + { + PolicyAction::Allow => Ok(()), + PolicyAction::Deny => Err(ZxError::ACCESS_DENIED), + _ => unimplemented!(), + } + } + + /// Get process status. + pub fn status(&self) -> Status { + self.inner.lock().status + } + + /// Get the `VmAddressRegion` of the process. + pub fn vmar(&self) -> Arc { + self.vmar.clone() + } + + /// Get the job of the process. + pub fn job(&self) -> Arc { + self.job.clone() + } + + /// Add a thread to the process. + pub(super) fn add_thread(&self, thread: Arc) -> ZxResult { + let mut inner = self.inner.lock(); + if let Status::Exited(_) = inner.status { + return Err(ZxError::BAD_STATE); + } + inner.threads.push(thread); + Ok(()) + } + + /// Remove a thread from the process. + /// + /// If no more threads left, exit the process. + pub(super) fn remove_thread(&self, tid: KoID) { + let mut inner = self.inner.lock(); + inner.threads.retain(|t| t.id() != tid); + if inner.threads.is_empty() { + drop(inner); + self.terminate(); + } + } + + /// Get KoIDs of Threads. + pub fn thread_ids(&self) -> Vec { + self.inner.lock().threads.iter().map(|t| t.id()).collect() + } + + /// Get information of this process. + pub fn get_info(&self) -> ProcessInfo { + let mut info = ProcessInfo { + ..Default::default() + }; + match self.inner.lock().status { + Status::Init => { + info.started = false; + info.has_exited = false; + } + Status::Running => { + info.started = true; + info.has_exited = false; + } + Status::Exited(ret) => { + info.return_code = ret; + info.has_exited = true; + info.started = true; + } + } + info + } +} + +/// Information of a process. +#[allow(missing_docs)] +#[repr(C)] +#[derive(Default)] +pub struct ProcessInfo { + pub return_code: i64, + pub started: bool, + pub has_exited: bool, +} + +impl Task for Process { + fn kill(&self) { + self.exit(TASK_RETCODE_SYSCALL_KILL); + } + + fn suspend(&self) { + // unimplemented!() + } + + fn resume(&self) { + // unimplemented!() + } +} + +impl ProcessInner { + /// Add a handle to the process + fn add_handle(&mut self, handle: Handle) -> HandleValue { + let key = (self.max_handle_id << 2) | 0x3u32; + self.max_handle_id += 1; + self.handles.insert(key, handle); + key + } + + fn remove_handle(&mut self, handle_value: HandleValue) -> ZxResult { + let handle = self + .handles + .remove(&handle_value) + .ok_or(ZxError::BAD_HANDLE)?; + Ok(handle) + } + + fn get_handle(&mut self, handle_value: HandleValue) -> ZxResult { + let handle = self.handles.get(&handle_value).ok_or(ZxError::BAD_HANDLE)?; + Ok(handle.clone()) + } + + /// Whether `thread` is in this process. + fn contains_thread(&self, thread: &Arc) -> bool { + self.threads.iter().any(|t| Arc::ptr_eq(t, thread)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn create() { + let root_job = Job::root(); + let proc = Process::create(&root_job, "proc").expect("failed to create process"); + + assert_eq!(proc.related_koid(), root_job.id()); + assert!(Arc::ptr_eq(&root_job, &proc.job())); + } + + #[test] + fn handle() { + let root_job = Job::root(); + let proc = Process::create(&root_job, "proc").expect("failed to create process"); + let handle = Handle::new(proc.clone(), Rights::DEFAULT_PROCESS); + + let handle_value = proc.add_handle(handle); + + // getting object should success + let object: Arc = proc + .get_object_with_rights(handle_value, Rights::DEFAULT_PROCESS) + .expect("failed to get object"); + assert!(Arc::ptr_eq(&object, &proc)); + + let (object, rights) = proc + .get_object_and_rights::(handle_value) + .expect("failed to get object"); + assert!(Arc::ptr_eq(&object, &proc)); + assert_eq!(rights, Rights::DEFAULT_PROCESS); + + // getting object with an extra rights should fail. + assert_eq!( + proc.get_object_with_rights::(handle_value, Rights::MANAGE_JOB) + .err(), + Some(ZxError::ACCESS_DENIED) + ); + + // getting object with invalid type should fail. + assert_eq!( + proc.get_object_with_rights::(handle_value, Rights::DEFAULT_PROCESS) + .err(), + Some(ZxError::WRONG_TYPE) + ); + + proc.remove_handle(handle_value).unwrap(); + + // getting object with invalid handle should fail. + assert_eq!( + proc.get_object_with_rights::(handle_value, Rights::DEFAULT_PROCESS) + .err(), + Some(ZxError::BAD_HANDLE) + ); + + let handle1 = Handle::new(proc.clone(), Rights::DEFAULT_PROCESS); + let handle2 = Handle::new(proc.clone(), Rights::DEFAULT_PROCESS); + + let handle_values = proc.add_handles(vec![handle1, handle2]); + let object1: Arc = proc + .get_object_with_rights(handle_values[0], Rights::DEFAULT_PROCESS) + .expect("failed to get object"); + assert!(Arc::ptr_eq(&object1, &proc)); + + proc.remove_handles(&handle_values).unwrap(); + assert_eq!( + proc.get_object_with_rights::(handle_values[0], Rights::DEFAULT_PROCESS) + .err(), + Some(ZxError::BAD_HANDLE) + ); + } + + #[test] + fn get_child() { + let root_job = Job::root(); + let proc = Process::create(&root_job, "proc").expect("failed to create process"); + let thread = Thread::create(&proc, "thread").expect("failed to create thread"); + + assert_eq!(proc.get_child(thread.id()).unwrap().id(), thread.id()); + assert_eq!(proc.get_child(proc.id()).err(), Some(ZxError::NOT_FOUND)); + + let thread1 = Thread::create(&proc, "thread1").expect("failed to create thread"); + assert_eq!(proc.thread_ids(), vec![thread.id(), thread1.id()]); + } + + #[test] + fn contains_thread() { + let root_job = Job::root(); + let proc = Process::create(&root_job, "proc").expect("failed to create process"); + let thread = Thread::create(&proc, "thread").expect("failed to create thread"); + + let proc1 = Process::create(&root_job, "proc1").expect("failed to create process"); + let thread1 = Thread::create(&proc1, "thread1").expect("failed to create thread"); + + let inner = proc.inner.lock(); + assert!(inner.contains_thread(&thread) && !inner.contains_thread(&thread1)); + } + + #[test] + fn check_policy() { + let root_job = Job::root(); + let policy1 = BasicPolicy { + condition: PolicyCondition::BadHandle, + action: PolicyAction::Allow, + }; + let policy2 = BasicPolicy { + condition: PolicyCondition::NewChannel, + action: PolicyAction::Deny, + }; + + assert!(root_job + .set_policy_basic(SetPolicyOptions::Absolute, &[policy1, policy2]) + .is_ok()); + let proc = Process::create(&root_job, "proc").expect("failed to create process"); + + assert!(proc.check_policy(PolicyCondition::BadHandle).is_ok()); + assert!(proc.check_policy(PolicyCondition::NewProcess).is_ok()); + assert_eq!( + proc.check_policy(PolicyCondition::NewChannel).err(), + Some(ZxError::ACCESS_DENIED) + ); + + let _job = root_job.create_child().unwrap(); + assert_eq!( + root_job + .set_policy_basic(SetPolicyOptions::Absolute, &[policy1, policy2]) + .err(), + Some(ZxError::BAD_STATE) + ); + } + + #[test] + fn exit() { + let root_job = Job::root(); + let proc = Process::create(&root_job, "proc").expect("failed to create process"); + + let info = proc.get_info(); + assert!(!info.has_exited && !info.started && info.return_code == 0); + + proc.exit(666); + let info = proc.get_info(); + assert!(info.has_exited && info.started && info.return_code == 666); + + assert_eq!( + Thread::create(&proc, "thread1").err(), + Some(ZxError::BAD_STATE) + ); + } } diff --git a/code/ch02-02/src/task/thread.rs b/code/ch02-02/src/task/thread.rs new file mode 100644 index 0000000..0c8ec4c --- /dev/null +++ b/code/ch02-02/src/task/thread.rs @@ -0,0 +1,24 @@ +use {super::process::Process, super::*, crate::object::*, alloc::sync::Arc}; + +pub struct Thread { + base: KObjectBase, + proc: Arc, +} + +impl_kobject!(Thread + fn related_koid(&self) -> KoID { + self.proc.id() + } +); + +impl Thread { + /// Create a new thread. + pub fn create(proc: &Arc, name: &str) -> ZxResult> { + let thread = Arc::new(Thread { + base: KObjectBase::with_name(name), + proc: proc.clone(), + }); + proc.add_thread(thread.clone())?; + Ok(thread) + } +} diff --git a/code/ch02-02/src/vm/mod.rs b/code/ch02-02/src/vm/mod.rs new file mode 100644 index 0000000..4739f77 --- /dev/null +++ b/code/ch02-02/src/vm/mod.rs @@ -0,0 +1,6 @@ +//! Objects for Virtual Memory Management. +use super::*; + +mod vmar; + +pub use self::vmar::*; diff --git a/code/ch02-02/src/vm/vmar.rs b/code/ch02-02/src/vm/vmar.rs new file mode 100644 index 0000000..4a78f4f --- /dev/null +++ b/code/ch02-02/src/vm/vmar.rs @@ -0,0 +1,17 @@ +use {super::*, crate::object::*, alloc::sync::Arc}; + +/// Virtual Memory Address Regions +pub struct VmAddressRegion { + base: KObjectBase, +} + +impl_kobject!(VmAddressRegion); + +impl VmAddressRegion { + /// Create a new root VMAR. + pub fn new_root() -> Arc { + Arc::new(VmAddressRegion { + base: KObjectBase::new(), + }) + } +}