LoGin 7b32f5080f
增加内存分配日志监视器 (#424)
* 完成内存日志监视,并输出日志到文件
* 修复进程退出后,procfs查看进程status文件会崩溃的问题
* 修复signal唤醒进程的判断条件问题
2023-11-07 21:39:27 +08:00

418 lines
14 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use core::intrinsics::unlikely;
use alloc::string::String;
use kdepends::thingbuf::mpsc::{
self,
errors::{TryRecvError, TrySendError},
};
use crate::libs::rwlock::RwLock;
pub mod init;
pub mod serial;
pub mod tty_device;
pub mod tty_driver;
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>,
// 前台进程,以后改成前台进程组
// front_job: Option<Pid>,
/// tty核心的状态
state: RwLock<TtyCoreState>,
}
#[derive(Debug)]
#[allow(dead_code)]
pub enum TtyError {
/// 缓冲区满,返回成功传送的字节数
BufferFull(usize),
/// 缓冲区空,返回成功传送的字节数
BufferEmpty(usize),
/// 设备已经被关闭
Closed,
/// End of file(已经读取的字符数包含eof)
EOF(usize),
/// 接收到信号终止
Stopped(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> {
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 {
let x = *val.unwrap();
buf[cnt] = x;
cnt += 1;
if unlikely(self.stdin_should_return(x)) {
return Ok(cnt);
}
}
}
return Ok(cnt);
}
fn stdin_should_return(&self, c: u8) -> bool {
// 如果是换行符或者是ctrl+d那么就应该返回
return c == b'\n' || c == 4;
}
/// @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 {
// TODO: 在这里考虑增加对信号发送的处理
// if buf[cnt] == 3 {
// let pid = ProcessManager::current_pcb().pid();
// Signal::SIGKILL.send_signal_info(
// Some(&mut SigInfo::new(
// Signal::SIGKILL,
// 0,
// SigCode::SI_USER,
// SigType::Kill(pid),
// )),
// pid,
// );
// return Err(TtyError::Stopped(cnt));
// }
*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]
#[allow(dead_code)]
pub fn disable_echo(&self) {
self.state.write().set(TtyCoreState::ECHO_ON, false);
}
/// @brief 判断当前tty核心是否开启了输入回显
///
/// @return true 开启了输入回显
///
/// @return false 未开启输入回显
#[inline]
#[allow(dead_code)]
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;
// }
// }
// }