ch1-3 完成 Channel 基础代码,还需要调整注释。

master
DeathWish5 5 years ago
parent cebda3390c
commit 3ce5e12629

@ -2,4 +2,5 @@
members = [
"ch01-01",
"ch01-02",
"ch01-03",
]

@ -0,0 +1,2 @@
target
Cargo.lock

@ -0,0 +1,13 @@
[package]
name = "ch01-03"
version = "0.1.0"
authors = ["Runji Wang <wangrunji0408@163.com>"]
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"

@ -0,0 +1,232 @@
// ANCHOR: result
///
pub type ZxResult<T = ()> = Result<T, ZxError>;
// 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

@ -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<Channel>,
recv_queue: Mutex<VecDeque<T>>,
next_txid: AtomicU32,
}
type T = MessagePacket;
type TxID = u32;
impl_kobject!(Channel
fn peer(&self) -> ZxResult<Arc<dyn KernelObject>> {
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<Self>, Arc<Self>) {
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<T> {
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<u8>,
/// See [Channel](struct.Channel.html) for details.
pub handles: Vec<Handle>,
}
#[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)
);
}
}

@ -0,0 +1,4 @@
use super::*;
mod channel;
pub use self::channel::*;

@ -0,0 +1,9 @@
#![no_std]
#![feature(get_mut_unchecked)]
extern crate alloc;
mod error;
mod ipc;
mod object;
mod task;

@ -0,0 +1,18 @@
// ANCHOR: handle
use super::{KernelObject, Rights};
use alloc::sync::Arc;
/// 内核对象句柄
#[derive(Clone)]
pub struct Handle {
pub object: Arc<dyn KernelObject>,
pub rights: Rights,
}
impl Handle {
/// 创建一个新句柄
pub fn new(object: Arc<dyn KernelObject>, rights: Rights) -> Self {
Handle { object, rights }
}
}
// ANCHOR_END: handle

@ -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<Arc<dyn KernelObject>> {
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<KObjectBaseInner>,
}
/// `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<Self> {
Arc::new(DummyObject {
base: KObjectBase::default(),
})
}
}
#[cfg(test)]
#[test]
fn impl_kobject() {
use alloc::format;
let dummy = DummyObject::new();
let object: Arc<dyn KernelObject> = 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<DummyObject> = object.downcast_arc::<DummyObject>().unwrap();
}

@ -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

@ -0,0 +1,3 @@
use super::*;
mod process;

@ -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<ProcessInner>,
}
impl_kobject!(Process);
struct ProcessInner {
handles: BTreeMap<HandleValue, Handle>,
}
pub type HandleValue = u32;
impl Process {
/// 创建一个新的进程对象
pub fn new() -> Arc<Self> {
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<T: KernelObject>(
&self,
handle_value: HandleValue,
desired_rights: Rights,
) -> ZxResult<Arc<T>> {
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::<T>()
.map_err(|_| ZxError::WRONG_TYPE)?;
if !handle.rights.contains(desired_rights) {
return Err(ZxError::ACCESS_DENIED);
}
Ok(object)
}
// ANCHOR_END: get_object_with_rights
}
Loading…
Cancel
Save