|
@@ -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<u8>,
|
|
|
|
+ stdin_tx: mpsc::Sender<u8>,
|
|
|
|
+ /// 输出的mpsc队列输入输出端
|
|
|
|
+ output_rx: mpsc::Receiver<u8>,
|
|
|
|
+ output_tx: mpsc::Sender<u8>,
|
|
|
|
+
|
|
|
|
+ /// tty核心的状态
|
|
|
|
+ state: RwLock<TtyCoreState>,
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#[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::<u8>(Self::STDIN_BUF_SIZE);
|
|
|
|
+ let (output_tx, output_rx) = mpsc::channel::<u8>(Self::OUTPUT_BUF_SIZE);
|
|
|
|
+ let state: RwLock<TtyCoreState> = 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<usize, TtyError> {
|
|
|
|
+ // 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<usize, TtyError> {
|
|
|
|
+ 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<usize, TtyError> {
|
|
|
|
+ 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<usize, TtyError> {
|
|
|
|
+ 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<usize, TtyError> {
|
|
|
|
+ // TODO: 增加对EOF的处理
|
|
|
|
+ let mut cnt = 0;
|
|
|
|
+ while cnt < buf.len() {
|
|
|
|
+ let val: Result<mpsc::RecvRef<u8>, 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<usize, TtyError> {
|
|
|
|
+ let mut cnt = 0;
|
|
|
|
+ while cnt < buf.len() {
|
|
|
|
+ let r: Result<mpsc::SendRef<u8>, 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<usize, TtyError> {
|
|
|
|
+ let mut cnt = 0;
|
|
|
|
+ while cnt < buf.len() {
|
|
|
|
+ let val: Result<mpsc::RecvRef<u8>, 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<usize, TtyError> {
|
|
|
|
+ let mut cnt = 0;
|
|
|
|
+ while cnt < buf.len() {
|
|
|
|
+ let r: Result<mpsc::SendRef<u8>, 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<usize, TtyError> {
|
|
|
|
+// let mut cnt = 0;
|
|
|
|
+// loop{
|
|
|
|
+// if cnt == buf.len(){
|
|
|
|
+// break;
|
|
|
|
+// }
|
|
|
|
+// let val:Option<u8> = self.stdin_queue.dequeue();
|
|
|
|
+// // 如果没读到
|
|
|
|
+// if val.is_none() {
|
|
|
|
+// // 如果阻塞读
|
|
|
|
+// if block {
|
|
|
|
+// let state_guard: RwLockUpgradableGuard<TtyCoreState> =
|
|
|
|
+// 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<TtyCoreState> = 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<u8> = 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<u8>) {
|
|
|
|
+// loop {
|
|
|
|
+// if let Some(val) = queue.dequeue() {
|
|
|
|
+// *dst = val;
|
|
|
|
+// return;
|
|
|
|
+// }
|
|
|
|
+// }
|
|
|
|
+// }
|