From 0d48c3c9c21a2dd470d0e1e58b507db60e0887bb Mon Sep 17 00:00:00 2001 From: login Date: Thu, 16 Mar 2023 19:48:59 +0800 Subject: [PATCH] =?UTF-8?q?new:=20tty=E8=AE=BE=E5=A4=87=EF=BC=88=E5=B0=9A?= =?UTF-8?q?=E6=9C=AA=E4=B8=8Estdio=E6=8E=A5=E4=B8=8A=EF=BC=89=20(#202)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/Cargo.toml | 3 +- kernel/src/driver/Makefile | 2 +- kernel/src/driver/disk/ahci/ahci_inode.rs | 3 +- kernel/src/driver/keyboard/ps2_keyboard.rs | 10 +- kernel/src/driver/mod.rs | 1 + kernel/src/driver/tty/Makefile | 8 - kernel/src/driver/tty/mod.rs | 384 +++++++++++++++++++++ kernel/src/driver/tty/tty.c | 92 ----- kernel/src/driver/tty/tty.h | 3 - kernel/src/driver/tty/tty_device.rs | 135 ++++++++ kernel/src/filesystem/devfs/mod.rs | 4 +- kernel/src/filesystem/devfs/null_dev.rs | 3 +- kernel/src/filesystem/devfs/zero_dev.rs | 3 +- kernel/src/filesystem/fat/fs.rs | 4 +- kernel/src/filesystem/procfs/mod.rs | 4 +- kernel/src/filesystem/vfs/file.rs | 10 +- kernel/src/filesystem/vfs/mod.rs | 3 +- kernel/src/filesystem/vfs/mount.rs | 6 +- kernel/src/io/device.rs | 1 + kernel/src/lib.rs | 2 +- kernel/src/main.c | 1 - kernel/src/process/process.rs | 19 +- 22 files changed, 572 insertions(+), 129 deletions(-) delete mode 100644 kernel/src/driver/tty/Makefile create mode 100644 kernel/src/driver/tty/mod.rs delete mode 100644 kernel/src/driver/tty/tty.c delete mode 100644 kernel/src/driver/tty/tty.h create mode 100644 kernel/src/driver/tty/tty_device.rs diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 03ee36b6..1f893dab 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -13,7 +13,8 @@ crate-type = ["staticlib"] x86_64 = "0.14.10" bitflags = "1.3.2" virtio-drivers = "0.2.0" - +# 一个无锁MPSC队列 +thingbuf = { version = "0.1.3", default-features = false, features = ["alloc"] } # 构建时依赖项 [build-dependencies] diff --git a/kernel/src/driver/Makefile b/kernel/src/driver/Makefile index 82f1ef39..e16d23a9 100644 --- a/kernel/src/driver/Makefile +++ b/kernel/src/driver/Makefile @@ -1,7 +1,7 @@ CFLAGS += -I . -kernel_driver_subdirs:=video interrupt usb pci acpi disk keyboard mouse multiboot2 timers tty hid virtio +kernel_driver_subdirs:=video interrupt usb pci acpi disk keyboard mouse multiboot2 timers hid virtio ECHO: @echo "$@" diff --git a/kernel/src/driver/disk/ahci/ahci_inode.rs b/kernel/src/driver/disk/ahci/ahci_inode.rs index 7fec3227..8e80fc2a 100644 --- a/kernel/src/driver/disk/ahci/ahci_inode.rs +++ b/kernel/src/driver/disk/ahci/ahci_inode.rs @@ -1,4 +1,5 @@ use crate::filesystem::devfs::{DevFS, DeviceINode}; +use crate::filesystem::vfs::file::FileMode; use crate::filesystem::vfs::{ core::generate_inode_id, make_rawdev, FilePrivateData, FileSystem, FileType, IndexNode, Metadata, PollStatus, @@ -77,7 +78,7 @@ impl IndexNode for LockedAhciInode { self } - fn open(&self, _data: &mut FilePrivateData) -> Result<(), i32> { + fn open(&self, _data: &mut FilePrivateData, _mode: &FileMode) -> Result<(), i32> { Err(-(ENOTSUP as i32)) } diff --git a/kernel/src/driver/keyboard/ps2_keyboard.rs b/kernel/src/driver/keyboard/ps2_keyboard.rs index 8fc64f2d..9b0d2ea0 100644 --- a/kernel/src/driver/keyboard/ps2_keyboard.rs +++ b/kernel/src/driver/keyboard/ps2_keyboard.rs @@ -3,7 +3,7 @@ use alloc::sync::{Arc, Weak}; use crate::{ filesystem::{ devfs::{devfs_register, DevFS, DeviceINode}, - vfs::{core::generate_inode_id, FileType, IndexNode, Metadata, PollStatus}, + vfs::{core::generate_inode_id, file::FileMode, FileType, IndexNode, Metadata, PollStatus}, }, include::bindings::bindings::{vfs_file_operations_t, vfs_file_t, vfs_index_node_t, ENOTSUP}, kdebug, @@ -68,10 +68,8 @@ impl DeviceINode for LockedPS2KeyBoardInode { #[no_mangle] // 不重命名 pub extern "C" fn ps2_keyboard_register(f_ops: &vfs_file_operations_t) { - kdebug!("register keyboard = {:p}", f_ops); devfs_register("ps2_keyboard", LockedPS2KeyBoardInode::new(f_ops)) .expect("Failed to register ps/2 keyboard"); - kdebug!("register keyboard = {:p}", f_ops); } impl IndexNode for LockedPS2KeyBoardInode { @@ -105,7 +103,11 @@ impl IndexNode for LockedPS2KeyBoardInode { return Err(-(ENOTSUP as i32)); } - fn open(&self, _data: &mut crate::filesystem::vfs::FilePrivateData) -> Result<(), i32> { + fn open( + &self, + _data: &mut crate::filesystem::vfs::FilePrivateData, + _mode: &FileMode, + ) -> Result<(), i32> { let guard = self.0.lock(); let func = guard.f_ops.open.unwrap(); let _ = unsafe { func(0 as *mut vfs_index_node_t, 0 as *mut vfs_file_t) }; diff --git a/kernel/src/driver/mod.rs b/kernel/src/driver/mod.rs index 84a59263..54f0b1b6 100644 --- a/kernel/src/driver/mod.rs +++ b/kernel/src/driver/mod.rs @@ -2,5 +2,6 @@ pub mod disk; pub mod keyboard; pub mod pci; pub mod timers; +pub mod tty; pub mod uart; pub mod virtio; diff --git a/kernel/src/driver/tty/Makefile b/kernel/src/driver/tty/Makefile deleted file mode 100644 index 5af16979..00000000 --- a/kernel/src/driver/tty/Makefile +++ /dev/null @@ -1,8 +0,0 @@ - -all: tty.o - -CFLAGS += -I . - - -tty.o: tty.c - $(CC) $(CFLAGS) -c tty.c -o tty.o \ No newline at end of file diff --git a/kernel/src/driver/tty/mod.rs b/kernel/src/driver/tty/mod.rs new file mode 100644 index 00000000..f4d9b162 --- /dev/null +++ b/kernel/src/driver/tty/mod.rs @@ -0,0 +1,384 @@ +use alloc::string::String; + +use thingbuf::mpsc::{ + self, + errors::{TryRecvError, TrySendError}, +}; + +use crate::libs::rwlock::RwLock; + +pub mod tty_device; + +bitflags! { + pub struct TtyCoreState: u32{ + /// 在读取stdin缓冲区时,由于队列为空,有读者被阻塞 + const BLOCK_AT_STDIN_READ = (1 << 0); + /// 开启输入回显。 + const ECHO_ON = (1 << 1); + } + + #[derive(Default)] + pub struct TtyFileFlag:u32{ + /// 当前文件是stdin文件 + const STDIN = (1 << 0); + /// 当前文件是stdout文件 + const STDOUT = (1 << 1); + /// 当前文件是stderr文件 + const STDERR = (1 << 2); + } +} + +/// @brief tty文件的私有信息 +#[derive(Debug, Default, Clone)] +pub struct TtyFilePrivateData { + flags: TtyFileFlag, +} + +/// @brief tty设备的核心功能结构体。在此结构体的基础上,衍生出TTY/PTY/PTS等 +/// +/// 每个TTY Core有5个端口: +/// - stdin:连接到一个活动进程的stdin文件描述符 +/// - stdout:连接到多个进程的stdout文件描述符 +/// - stderr:连接到多个进程的stdout文件描述符 +/// - 输入端口:向tty设备输入数据的接口。输入到该接口的数据,将被导向stdin接口。 +/// 如果开启了回显,那么,数据也将同时被导向输出端 +/// - 输出端口:tty设备对外输出数据的端口。从stdout、stderr输入的数据,将会被导向此端口。 +/// 此端口可以连接到屏幕、文件、或者是另一个tty core的输入端口。如果开启了 +/// 输入数据回显,那么,输入端口的数据,将会被同时导向此端口,以及stdin端口 +#[derive(Debug)] +struct TtyCore { + /// stdin的mpsc队列输入输出端 + stdin_rx: mpsc::Receiver, + stdin_tx: mpsc::Sender, + /// 输出的mpsc队列输入输出端 + output_rx: mpsc::Receiver, + output_tx: mpsc::Sender, + + /// tty核心的状态 + state: RwLock, +} + +#[derive(Debug)] +pub enum TtyError { + /// 缓冲区满,返回成功传送的字节数 + BufferFull(usize), + /// 缓冲区空,返回成功传送的字节数 + BufferEmpty(usize), + /// 设备已经被关闭 + Closed, + /// End of file(已经读取的字符数,包含eof) + EOF(usize), + Unknown(String), +} + +impl TtyCore { + // 各个缓冲区的大小 + pub const STDIN_BUF_SIZE: usize = 4096; + pub const OUTPUT_BUF_SIZE: usize = 4096; + + /// @brief 创建一个TTY核心组件 + pub fn new() -> TtyCore { + let (stdin_tx, stdin_rx) = mpsc::channel::(Self::STDIN_BUF_SIZE); + let (output_tx, output_rx) = mpsc::channel::(Self::OUTPUT_BUF_SIZE); + let state: RwLock = RwLock::new(TtyCoreState { bits: 0 }); + + return TtyCore { + stdin_rx, + stdin_tx, + output_rx, + output_tx, + state, + }; + } + + /// @brief 向tty的输入端口输入数据 + /// + /// @param buf 输入数据 + /// + /// @param block 是否允许阻塞 + /// + /// @return Ok(成功传送的字节数) + /// @return Err(TtyError) 内部错误信息 + pub fn input(&self, buf: &[u8], block: bool) -> Result { + // TODO: 在这里考虑增加对信号发送的处理 + let val = self.write_stdin(buf, block)?; + // 如果开启了输入回显,那么就写一份到输出缓冲区 + if self.echo_enabled() { + self.write_output(&buf[0..val], true)?; + } + return Ok(val); + } + + /// @brief 从tty的输出端口读出数据 + /// + /// @param buf 输出缓冲区 + /// + /// @return Ok(成功传送的字节数) + /// @return Err(TtyError) 内部错误信息 + #[inline] + pub fn output(&self, buf: &mut [u8], block: bool) -> Result { + return self.read_output(buf, block); + } + + /// @brief tty的stdout接口 + /// + /// @param buf 输入缓冲区 + /// + /// @return Ok(成功传送的字节数) + /// @return Err(TtyError) 内部错误信息 + #[inline] + pub fn stdout(&self, buf: &[u8], block: bool) -> Result { + return self.write_output(buf, block); + } + + /// @brief tty的stderr接口 + /// + /// @param buf 输入缓冲区 + /// + /// @return Ok(成功传送的字节数) + /// @return Err(TtyError) 内部错误信息 + #[inline] + pub fn stderr(&self, buf: &[u8], block: bool) -> Result { + return self.write_output(buf, block); + } + + /// @brief 读取TTY的stdin缓冲区 + /// + /// @param buf 读取到的位置 + /// @param block 是否阻塞读 + /// + /// @return Ok(成功读取的字节数) + /// @return Err(TtyError) 内部错误信息 + pub fn read_stdin(&self, buf: &mut [u8], block: bool) -> Result { + // TODO: 增加对EOF的处理 + let mut cnt = 0; + while cnt < buf.len() { + let val: Result, TryRecvError> = self.stdin_rx.try_recv_ref(); + if let Err(err) = val { + match err { + TryRecvError::Closed => return Err(TtyError::Closed), + TryRecvError::Empty => { + if block { + continue; + } else { + return Ok(cnt); + } + } + _ => return Err(TtyError::Unknown(format!("{err:?}"))), + } + } else { + buf[cnt] = *val.unwrap(); + cnt += 1; + } + } + return Ok(cnt); + } + + /// @brief 向stdin缓冲区内写入数据 + /// + /// @param buf 输入缓冲区 + /// + /// @param block 当缓冲区满的时候,是否阻塞 + /// + /// @return Ok(成功传送的字节数) + /// @return Err(BufferFull(成功传送的字节数)) 缓冲区满,成功传送的字节数 + /// @return Err(TtyError) 内部错误信息 + fn write_stdin(&self, buf: &[u8], block: bool) -> Result { + let mut cnt = 0; + while cnt < buf.len() { + let r: Result, TrySendError> = self.stdin_tx.try_send_ref(); + if let Err(e) = r { + match e { + TrySendError::Closed(_) => return Err(TtyError::Closed), + TrySendError::Full(_) => { + if block { + continue; + } else { + return Err(TtyError::BufferFull(cnt)); + } + } + _ => return Err(TtyError::Unknown(format!("{e:?}"))), + } + } else { + *r.unwrap() = buf[cnt]; + cnt += 1; + } + } + + return Ok(cnt); + } + + /// @brief 读取TTY的output缓冲区 + /// + /// @param buf 读取到的位置 + /// @param block 是否阻塞读 + /// + /// @return Ok(成功读取的字节数) + /// @return Err(TtyError) 内部错误信息 + fn read_output(&self, buf: &mut [u8], block: bool) -> Result { + let mut cnt = 0; + while cnt < buf.len() { + let val: Result, TryRecvError> = self.output_rx.try_recv_ref(); + if let Err(err) = val { + match err { + TryRecvError::Closed => return Err(TtyError::Closed), + TryRecvError::Empty => { + if block { + continue; + } else { + return Ok(cnt); + } + } + _ => return Err(TtyError::Unknown(format!("{err:?}"))), + } + } else { + buf[cnt] = *val.unwrap(); + cnt += 1; + } + } + return Ok(cnt); + } + + /// @brief 向output缓冲区内写入数据 + /// + /// @param buf 输入缓冲区 + /// + /// @param block 当缓冲区满的时候,是否阻塞 + /// + /// @return Ok(成功传送的字节数) + /// @return Err(BufferFull(成功传送的字节数)) 缓冲区满,成功传送的字节数 + /// @return Err(TtyError) 内部错误信息 + fn write_output(&self, buf: &[u8], block: bool) -> Result { + let mut cnt = 0; + while cnt < buf.len() { + let r: Result, TrySendError> = self.output_tx.try_send_ref(); + if let Err(e) = r { + match e { + TrySendError::Closed(_) => return Err(TtyError::Closed), + TrySendError::Full(_) => { + if block { + continue; + } else { + return Err(TtyError::BufferFull(cnt)); + } + } + _ => return Err(TtyError::Unknown(format!("{e:?}"))), + } + } else { + *r.unwrap() = buf[cnt]; + cnt += 1; + } + } + + return Ok(cnt); + } + + /// @brief 开启tty输入回显(也就是将输入数据传送一份到输出缓冲区) + #[inline] + pub fn enable_echo(&self) { + self.state.write().set(TtyCoreState::ECHO_ON, true); + } + + /// @brief 关闭输入回显 + #[inline] + pub fn disable_echo(&self) { + self.state.write().set(TtyCoreState::ECHO_ON, false); + } + + /// @brief 判断当前tty核心,是否开启了输入回显 + /// + /// @return true 开启了输入回显 + /// + /// @return false 未开启输入回显 + #[inline] + pub fn echo_enabled(&self) -> bool { + return self.state.read().contains(TtyCoreState::ECHO_ON); + } +} + +// ======= 以下代码考虑了“缓冲区满,然后睡眠,当缓冲区有空位就唤醒”的逻辑。 +// 但是由于在开发过程中的调整,并且由于数据结构发生变化,因此暂时不实现上述优化,因此先注释。 +// +// @brief 读取TTY的stdin缓冲区 +// +// @param buf 读取到的位置 +// @param block 是否阻塞读 +// +// @return Ok(成功读取的字节数) +// @return Err(TtyError) 内部错误信息 +// pub fn read_stdin(&mut self, buf: &mut [u8], block: bool) -> Result { +// let mut cnt = 0; +// loop{ +// if cnt == buf.len(){ +// break; +// } +// let val:Option = self.stdin_queue.dequeue(); +// // 如果没读到 +// if val.is_none() { +// // 如果阻塞读 +// if block { +// let state_guard: RwLockUpgradableGuard = +// self.state.upgradeable_read(); +// // 判断是否有进程正在stdin上睡眠,如果有,则忙等读 +// // 理论上,这种情况应该不存在,因为stdin是单读者的 +// if state_guard.contains(TtyCoreState::BLOCK_AT_STDIN_READ) { +// kwarn!("Read stdin: Process {} want to read its' stdin, but previous process {} is sleeping on the stdin.", current_pcb().pid, self.stdin_waiter.read().as_ref().unwrap().pid); +// drop(state_guard); +// Self::ringbuf_spin_dequeue(&mut buf[cnt], &mut self.stdin_queue); +// cnt += 1; +// } else { +// // 正常情况,阻塞读,将当前进程休眠 +// let mut state_guard: RwLockWriteGuard = state_guard.upgrade(); +// let mut stdin_waiter_guard: RwLockWriteGuard< +// Option<&mut process_control_block>, +// > = self.stdin_waiter.write(); + +// // 由于输入数据到stdin的时候,必须先获得state guard的读锁。而这里我们已经获取了state的写锁。 +// // 因此可以保证,此时没有新的数据会进入stdin_queue. 因此再次尝试读取stdin_queue +// let val:Option = self.stdin_queue.dequeue(); +// // 读到数据,不用睡眠 +// if val.is_some(){ +// buf[cnt] = val.unwrap(); +// cnt += 1; +// continue; +// } +// // 没读到数据,准备睡眠 + +// // 设置等待标志位 +// state_guard.set(TtyCoreState::BLOCK_AT_STDIN_READ, true); + +// // 将当前进程标记为被其他机制管理 +// unsafe { +// current_pcb().mark_sleep_interruptible(); +// } + +// *stdin_waiter_guard = Some(current_pcb()); +// drop(stdin_waiter_guard); +// drop(state_guard); +// sched(); +// continue; +// } +// } else { +// // 非阻塞读,没读到就直接返回了 +// return Ok(cnt); +// } +// }else{ +// buf[cnt] = val.unwrap(); +// cnt += 1; +// } +// } + +// return Ok(cnt); +// } + +// fn write_stdin(&self) + +// /// @brief 非休眠的,自旋地读队列,直到有元素被读出来 +// fn ringbuf_spin_dequeue(dst: &mut u8, queue: &mut AllocRingBuffer) { +// loop { +// if let Some(val) = queue.dequeue() { +// *dst = val; +// return; +// } +// } +// } diff --git a/kernel/src/driver/tty/tty.c b/kernel/src/driver/tty/tty.c deleted file mode 100644 index b2d96cbf..00000000 --- a/kernel/src/driver/tty/tty.c +++ /dev/null @@ -1,92 +0,0 @@ -#include -#include "tty.h" - -static struct devfs_private_inode_info_t * tty_inode_private_data_ptr; // 由devfs创建的inode私有信息指针 -static int tty_private_data; - -/** - * @brief 打开tty文件 - * - * @param inode 所在的inode - * @param filp 文件指针 - * @return long - */ -long tty_open(struct vfs_index_node_t *inode, struct vfs_file_t *filp) -{ - filp->private_data = &tty_private_data; - return 0; -} - -/** - * @brief 关闭tty文件 - * - * @param inode 所在的inode - * @param filp 文件指针 - * @return long - */ -long tty_close(struct vfs_index_node_t *inode, struct vfs_file_t *filp) -{ - filp->private_data = NULL; - return 0; -} - -/** - * @brief tty控制接口 - * - * @param inode 所在的inode - * @param filp tty文件指针 - * @param cmd 命令 - * @param arg 参数 - * @return long - */ -long tty_ioctl(struct vfs_index_node_t *inode, struct vfs_file_t *filp, uint64_t cmd, uint64_t arg) -{ - switch (cmd) - { - default: - break; - } - return 0; -} - -/** - * @brief 读取tty文件的操作接口 - * - * @param filp 文件指针 - * @param buf 输出缓冲区 - * @param count 要读取的字节数 - * @param position 读取的位置 - * @return long 读取的字节数 - */ -long tty_read(struct vfs_file_t *filp, char *buf, int64_t count, long *position) -{ - return 0; -} - -/** - * @brief tty文件写入接口(无作用,空) - * - * @param filp - * @param buf - * @param count - * @param position - * @return long - */ -long tty_write(struct vfs_file_t *filp, char *buf, int64_t count, long *position) -{ - return 0; -} - -struct vfs_file_operations_t tty_fops={ - .open = tty_open, - .close = tty_close, - .ioctl = tty_ioctl, - .read = tty_read, - .write = tty_write, -}; - -// void tty_init(){ -// //注册devfs -// devfs_register_device(DEV_TYPE_CHAR, CHAR_DEV_STYPE_TTY, &tty_fops, &tty_inode_private_data_ptr); -// kinfo("tty driver registered. uuid=%d", tty_inode_private_data_ptr->uuid); -// } \ No newline at end of file diff --git a/kernel/src/driver/tty/tty.h b/kernel/src/driver/tty/tty.h deleted file mode 100644 index d35cb68f..00000000 --- a/kernel/src/driver/tty/tty.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -void tty_init(); \ No newline at end of file diff --git a/kernel/src/driver/tty/tty_device.rs b/kernel/src/driver/tty/tty_device.rs new file mode 100644 index 00000000..1f08761d --- /dev/null +++ b/kernel/src/driver/tty/tty_device.rs @@ -0,0 +1,135 @@ +use alloc::sync::{Arc, Weak}; + +use crate::{ + filesystem::{ + devfs::{DeviceINode, DevFS}, + vfs::{file::FileMode, FilePrivateData, IndexNode}, + }, + include::bindings::bindings::{ECONNABORTED, EIO, ENOTSUP, EPERM}, + kerror, libs::rwlock::RwLock, +}; + +use super::{TtyCore, TtyError, TtyFileFlag, TtyFilePrivateData}; + +#[derive(Debug)] +pub struct TtyDevice { + core: TtyCore, + fs: RwLock> + +} + +impl TtyDevice { + pub fn new() -> Arc { + return Arc::new(TtyDevice { + core: TtyCore::new(), + fs: RwLock::new(Weak::default()), + }); + } + + /// @brief 判断文件私有信息是否为TTY的私有信息 + #[inline] + fn verify_file_private_data<'a>( + &self, + private_data: &'a mut FilePrivateData, + ) -> Result<&'a mut TtyFilePrivateData, i32> { + if let FilePrivateData::Tty(t) = private_data { + return Ok(t); + } + return Err(-(EIO as i32)); + } +} + +impl DeviceINode for TtyDevice { + fn set_fs(&self, fs: alloc::sync::Weak) { + *self.fs.write() = fs; + } +} + +impl IndexNode for TtyDevice { + fn open(&self, data: &mut FilePrivateData, mode: &FileMode) -> Result<(), i32> { + let p = TtyFilePrivateData::default(); + *data = FilePrivateData::Tty(p); + return Ok(()); + } + + fn read_at( + &self, + offset: usize, + len: usize, + buf: &mut [u8], + data: &mut crate::filesystem::vfs::FilePrivateData, + ) -> Result { + let _data: &mut TtyFilePrivateData = match self.verify_file_private_data(data) { + Ok(t) => t, + Err(e) => { + kerror!("Try to read tty device, but file private data type mismatch!"); + return Err(e); + } + }; + + // 读取stdin队列 + let r: Result = self.core.read_stdin(buf, true); + if r.is_ok() { + return Ok(r.unwrap()); + } + + match r.unwrap_err() { + TtyError::EOF(n) => { + return Ok(n); + } + x => { + kerror!("Error occurred when reading tty, msg={x:?}"); + return Err(-(ECONNABORTED as i32)); + } + } + } + + fn write_at( + &self, + offset: usize, + len: usize, + buf: &[u8], + data: &mut crate::filesystem::vfs::FilePrivateData, + ) -> Result { + let data: &mut TtyFilePrivateData = match self.verify_file_private_data(data) { + Ok(t) => t, + Err(e) => { + kerror!("Try to write tty device, but file private data type mismatch!"); + return Err(e); + } + }; + + // 根据当前文件是stdout还是stderr,选择不同的发送方式 + let r: Result = if data.flags.contains(TtyFileFlag::STDOUT) { + self.core.stdout(buf, true) + } else if data.flags.contains(TtyFileFlag::STDERR) { + self.core.stderr(buf, true) + } else { + return Err(-(EPERM as i32)); + }; + + if r.is_ok() { + return Ok(r.unwrap()); + } + + let r: TtyError = r.unwrap_err(); + kerror!("Error occurred when writing tty deivce. Error msg={r:?}"); + return Err(-(EIO as i32)); + } + + fn poll(&self) -> Result { + return Err(-(ENOTSUP as i32)); + } + + fn fs(&self) -> Arc { + return self.fs.read().upgrade().unwrap(); + } + + fn as_any_ref(&self) -> &dyn core::any::Any { + self + } + + fn list(&self) -> Result, i32> { + return Err(-(ENOTSUP as i32)); + } +} diff --git a/kernel/src/filesystem/devfs/mod.rs b/kernel/src/filesystem/devfs/mod.rs index daf68472..c83bdeb6 100644 --- a/kernel/src/filesystem/devfs/mod.rs +++ b/kernel/src/filesystem/devfs/mod.rs @@ -4,7 +4,7 @@ pub mod zero_dev; use super::vfs::{ core::{generate_inode_id, ROOT_INODE}, - FileSystem, FileType, FsInfo, IndexNode, Metadata, PollStatus, + FileSystem, FileType, FsInfo, IndexNode, Metadata, PollStatus, file::FileMode, }; use crate::{ include::bindings::bindings::{EEXIST, EISDIR, ENOENT, ENOTDIR, ENOTSUP}, @@ -322,7 +322,7 @@ impl IndexNode for LockedDevFSInode { self } - fn open(&self, _data: &mut super::vfs::FilePrivateData) -> Result<(), i32> { + fn open(&self, _data: &mut super::vfs::FilePrivateData, _mode: &FileMode) -> Result<(), i32> { return Ok(()); } diff --git a/kernel/src/filesystem/devfs/null_dev.rs b/kernel/src/filesystem/devfs/null_dev.rs index 83fa2457..5035fad5 100644 --- a/kernel/src/filesystem/devfs/null_dev.rs +++ b/kernel/src/filesystem/devfs/null_dev.rs @@ -1,3 +1,4 @@ +use crate::filesystem::vfs::file::FileMode; use crate::filesystem::vfs::make_rawdev; use crate::filesystem::vfs::{ core::generate_inode_id, FilePrivateData, FileSystem, FileType, IndexNode, Metadata, PollStatus, @@ -72,7 +73,7 @@ impl IndexNode for LockedNullInode { self } - fn open(&self, _data: &mut FilePrivateData) -> Result<(), i32> { + fn open(&self, _data: &mut FilePrivateData, _mode: &FileMode) -> Result<(), i32> { Err(-(ENOTSUP as i32)) } diff --git a/kernel/src/filesystem/devfs/zero_dev.rs b/kernel/src/filesystem/devfs/zero_dev.rs index 25762108..692ceda3 100644 --- a/kernel/src/filesystem/devfs/zero_dev.rs +++ b/kernel/src/filesystem/devfs/zero_dev.rs @@ -1,3 +1,4 @@ +use crate::filesystem::vfs::file::FileMode; use crate::filesystem::vfs::make_rawdev; use crate::filesystem::vfs::{ core::generate_inode_id, FilePrivateData, FileSystem, FileType, IndexNode, Metadata, PollStatus, @@ -72,7 +73,7 @@ impl IndexNode for LockedZeroInode { self } - fn open(&self, _data: &mut FilePrivateData) -> Result<(), i32> { + fn open(&self, _data: &mut FilePrivateData, _mode: &FileMode) -> Result<(), i32> { Err(-(ENOTSUP as i32)) } diff --git a/kernel/src/filesystem/fat/fs.rs b/kernel/src/filesystem/fat/fs.rs index 1f16eb92..2546e514 100644 --- a/kernel/src/filesystem/fat/fs.rs +++ b/kernel/src/filesystem/fat/fs.rs @@ -10,7 +10,7 @@ use alloc::{ use crate::{ filesystem::vfs::{ - core::generate_inode_id, file::FilePrivateData, FileSystem, FileType, IndexNode, InodeId, + core::generate_inode_id, file::{FilePrivateData, FileMode}, FileSystem, FileType, IndexNode, InodeId, Metadata, PollStatus, }, include::bindings::bindings::{ @@ -1506,7 +1506,7 @@ impl IndexNode for LockedFATInode { return Ok(target); } - fn open(&self, _data: &mut FilePrivateData) -> Result<(), i32> { + fn open(&self, _data: &mut FilePrivateData, _mode: &FileMode) -> Result<(), i32> { return Ok(()); } diff --git a/kernel/src/filesystem/procfs/mod.rs b/kernel/src/filesystem/procfs/mod.rs index c0c2be40..b1a5ca37 100644 --- a/kernel/src/filesystem/procfs/mod.rs +++ b/kernel/src/filesystem/procfs/mod.rs @@ -24,7 +24,7 @@ use crate::{ }; use super::vfs::{ - file::FilePrivateData, FileSystem, FsInfo, IndexNode, InodeId, Metadata, PollStatus, + file::{FilePrivateData, FileMode}, FileSystem, FsInfo, IndexNode, InodeId, Metadata, PollStatus, }; /// @brief 进程文件类型 @@ -319,7 +319,7 @@ impl ProcFS { } impl IndexNode for LockedProcFSInode { - fn open(&self, data: &mut FilePrivateData) -> Result<(), i32> { + fn open(&self, data: &mut FilePrivateData, _mode: &FileMode) -> Result<(), i32> { // 加锁 let mut inode: SpinLockGuard = self.0.lock(); diff --git a/kernel/src/filesystem/vfs/file.rs b/kernel/src/filesystem/vfs/file.rs index 33903079..ab84e2bd 100644 --- a/kernel/src/filesystem/vfs/file.rs +++ b/kernel/src/filesystem/vfs/file.rs @@ -9,7 +9,7 @@ use crate::{ process_control_block, EINVAL, ENOBUFS, EOVERFLOW, EPERM, ESPIPE, }, io::SeekFrom, - kerror, + kerror, driver::tty::TtyFilePrivateData, }; use super::{Dirent, FileType, IndexNode, Metadata}; @@ -17,9 +17,11 @@ use super::{Dirent, FileType, IndexNode, Metadata}; /// 文件私有信息的枚举类型 #[derive(Debug, Clone)] pub enum FilePrivateData { - // procfs文件私有信息 + /// procfs文件私有信息 Procfs(ProcfsFilePrivateData), - // 不需要文件私有信息 + /// Tty设备的私有信息 + Tty(TtyFilePrivateData), + /// 不需要文件私有信息 Unused, } @@ -107,7 +109,7 @@ impl File { private_data: FilePrivateData::default(), }; // kdebug!("inode:{:?}",f.inode); - f.inode.open(&mut f.private_data)?; + f.inode.open(&mut f.private_data, &mode)?; return Ok(f); } diff --git a/kernel/src/filesystem/vfs/mod.rs b/kernel/src/filesystem/vfs/mod.rs index f792f5fb..457a1291 100644 --- a/kernel/src/filesystem/vfs/mod.rs +++ b/kernel/src/filesystem/vfs/mod.rs @@ -15,6 +15,7 @@ use crate::{ time::TimeSpec, }; +use self::file::FileMode; pub use self::{core::ROOT_INODE, file::FilePrivateData, mount::MountFS}; /// vfs容许的最大的路径名称长度 @@ -91,7 +92,7 @@ pub trait IndexNode: Any + Sync + Send + Debug { /// /// @return 成功:Ok() /// 失败:Err(错误码) - fn open(&self, _data: &mut FilePrivateData) -> Result<(), i32> { + fn open(&self, _data: &mut FilePrivateData, _mode: &FileMode) -> Result<(), i32> { // 若文件系统没有实现此方法,则返回“不支持” return Err(-(ENOTSUP as i32)); } diff --git a/kernel/src/filesystem/vfs/mount.rs b/kernel/src/filesystem/vfs/mount.rs index ee86496f..f19a5f30 100644 --- a/kernel/src/filesystem/vfs/mount.rs +++ b/kernel/src/filesystem/vfs/mount.rs @@ -10,7 +10,7 @@ use crate::{ libs::spinlock::SpinLock, }; -use super::{FilePrivateData, FileSystem, FileType, IndexNode, InodeId}; +use super::{FilePrivateData, FileSystem, FileType, IndexNode, InodeId, file::FileMode}; /// @brief 挂载文件系统 /// 挂载文件系统的时候,套了MountFS这一层,以实现文件系统的递归挂载 @@ -126,8 +126,8 @@ impl MountFSInode { } impl IndexNode for MountFSInode { - fn open(&self, data: &mut FilePrivateData) -> Result<(), i32> { - return self.inner_inode.open(data); + fn open(&self, data: &mut FilePrivateData, mode: &FileMode) -> Result<(), i32> { + return self.inner_inode.open(data, mode); } fn close(&self, data: &mut FilePrivateData) -> Result<(), i32> { diff --git a/kernel/src/io/device.rs b/kernel/src/io/device.rs index 2e593207..b4c28fa6 100644 --- a/kernel/src/io/device.rs +++ b/kernel/src/io/device.rs @@ -45,6 +45,7 @@ pub trait Device: Any + Send + Sync + Debug { fn sync(&self) -> Result<(), i32>; // TODO: 待实现 open, close + } /// @brief 块设备应该实现的操作 diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 85ec8481..c269d80d 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -38,7 +38,7 @@ extern crate lazy_static; #[macro_use] extern crate bitflags; - +extern crate thingbuf; use mm::allocator::KernelAllocator; diff --git a/kernel/src/main.c b/kernel/src/main.c index 5e3e3fb5..8e8016cc 100644 --- a/kernel/src/main.c +++ b/kernel/src/main.c @@ -28,7 +28,6 @@ #include "driver/mouse/ps2_mouse.h" #include "driver/multiboot2/multiboot2.h" #include "driver/pci/pci.h" -#include "driver/tty/tty.h" #include #include #include diff --git a/kernel/src/process/process.rs b/kernel/src/process/process.rs index 355fa151..e4ed92c9 100644 --- a/kernel/src/process/process.rs +++ b/kernel/src/process/process.rs @@ -9,7 +9,8 @@ use crate::{ arch::asm::current::current_pcb, filesystem::vfs::file::{File, FileDescriptorVec}, include::bindings::bindings::{ - process_control_block, CLONE_FS, EBADF, EFAULT, ENFILE, EPERM, PROC_RUNNING, PROC_STOPPED, + process_control_block, CLONE_FS, EBADF, EFAULT, ENFILE, EPERM, PROC_INTERRUPTIBLE, + PROC_RUNNING, PROC_STOPPED, PROC_UNINTERRUPTIBLE, }, sched::core::{cpu_executing, sched_enqueue}, smp::core::{smp_get_processor_id, smp_send_reschedule}, @@ -253,6 +254,22 @@ impl process_control_block { return Ok(()); } + + /// @brief 标记当前pcb已经由其他机制进行管理,调度器将不会将他加入队列(且进程可以被信号打断) + /// 当我们要把一个进程,交给其他机制管理时,那么就应该调用本函数。 + /// + /// 由于本函数可能造成进程不再被调度,因此标记为unsafe + pub unsafe fn mark_sleep_interruptible(&mut self){ + self.state = PROC_INTERRUPTIBLE as u64; + } + + /// @brief 标记当前pcb已经由其他机制进行管理,调度器将不会将他加入队列(且进程不可以被信号打断) + /// 当我们要把一个进程,交给其他机制管理时,那么就应该调用本函数 + /// + /// 由于本函数可能造成进程不再被调度,因此标记为unsafe + pub unsafe fn mark_sleep_uninterruptible(&mut self){ + self.state = PROC_UNINTERRUPTIBLE as u64; + } } // =========== 导出到C的函数,在将来,进程管理模块被完全重构之后,需要删掉他们 BEGIN ============