自定义请求类型

我们之前看到了内核线程中维护了一个请求队列,这个请求数据结构实际上就是一个字节的队列:

/// 用户向内核线程发送的请求
///
/// 用户发送请求时将其转化为字节,用户态再重新解析
pub type Request = Vec<u8>;

用户线程在发送请求时将请求类型转为字节,内核线程在处理请求时需要将字节解析为具体的请求类型,为此定义一个请求和字节相互转化的trait:

/// 用户请求信息和字节切片相互转化
pub trait CastBytes {
    /// 将请求转化为字节数组。
    /// 请求在发送给组件对象时,会被转化为字节数组。在实际处理时,才会转化回具体的请求类型
    fn as_bytes(&self) -> &[u8]
    where
        Self: Sized,
    {
        let data = self as *const Self as *const u8;
        let len = core::mem::size_of_val(self);
        unsafe { core::slice::from_raw_parts(data, len) }
    }

    /// 将字节数组转化为请求
    fn from_bytes(bytes: &[u8]) -> &Self
    where
        Self: Sized,
    {
        assert_eq!(bytes.len(), core::mem::size_of::<Self>());
        let ptr = bytes.as_ptr() as *const Self;
        unsafe { ptr.as_ref().unwrap() }
    }
}

再为用户定义的请求类型实现这个trait,下面以文件系统请求为例:

pub type Fd = usize;
pub type Pid = usize;
pub type BufPtr = usize;
pub type BufLen = usize;
pub type PathPtr = usize;
pub type FLAGS = u32;
pub type FdPtr = usize;
pub type ResultPtr = usize;

/// 文件系统类请求描述信息
#[derive(Debug, Clone, Copy)]
pub enum FsReqDescription {
    /// 读磁盘文件,在sys_read中被构造
    Read(Pid, Fd, BufPtr, BufLen, ResultPtr),
    /// 写磁盘文件,在sys_write中被构造
    Write(Pid, Fd, BufPtr, BufLen, ResultPtr),
    /// 打开一个磁盘文件,将句柄写入FdPtr中,
    /// 在sys_open中构造
    Open(Pid, PathPtr, FLAGS, FdPtr),
}

impl CastBytes for FsReqDescription {}

目前文件系统内核线程处理ReadWriteOpen三种请求,因为这三种文件系统操作都涉及到底层的块设备操作,会调用块设备驱动程序,所以我们认为其是不可靠的。

我们会在后面介绍内核线程是如何解析并处理这些请求的。