mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 18:26:48 +00:00
能够在系统调用返回ERESTARTSYS时,信号处理结束后,自动重启系统调用. TODO: 实现wait等需要restart_block的系统调用的重启 Signed-off-by: longjin <longjin@DragonOS.org>
2126 lines
69 KiB
Rust
2126 lines
69 KiB
Rust
use core::intrinsics::likely;
|
||
use core::ops::BitXor;
|
||
|
||
use bitmap::{traits::BitMapOps, StaticBitmap};
|
||
|
||
use alloc::sync::{Arc, Weak};
|
||
use system_error::SystemError;
|
||
|
||
use crate::{
|
||
arch::ipc::signal::Signal,
|
||
driver::tty::{
|
||
termios::{ControlCharIndex, InputMode, LocalMode, OutputMode, Termios},
|
||
tty_core::{EchoOperation, TtyCore, TtyCoreData, TtyFlag, TtyIoctlCmd, TtyPacketStatus},
|
||
tty_driver::{TtyDriverFlag, TtyOperation},
|
||
tty_job_control::TtyJobCtrlManager,
|
||
},
|
||
filesystem::vfs::file::FileMode,
|
||
libs::{
|
||
rwlock::RwLockReadGuard,
|
||
spinlock::{SpinLock, SpinLockGuard},
|
||
},
|
||
mm::VirtAddr,
|
||
net::event_poll::EPollEventType,
|
||
process::{ProcessFlags, ProcessManager},
|
||
syscall::{user_access::UserBufferWriter, Syscall},
|
||
};
|
||
|
||
use super::TtyLineDiscipline;
|
||
pub const NTTY_BUFSIZE: usize = 4096;
|
||
pub const ECHO_COMMIT_WATERMARK: usize = 256;
|
||
pub const ECHO_BLOCK: usize = 256;
|
||
pub const ECHO_DISCARD_WATERMARK: usize = NTTY_BUFSIZE - (ECHO_BLOCK + 32);
|
||
|
||
fn ntty_buf_mask(idx: usize) -> usize {
|
||
return idx & (NTTY_BUFSIZE - 1);
|
||
}
|
||
|
||
#[derive(Debug)]
|
||
pub struct NTtyLinediscipline {
|
||
pub data: SpinLock<NTtyData>,
|
||
}
|
||
|
||
impl NTtyLinediscipline {
|
||
#[inline]
|
||
pub fn disc_data(&self) -> SpinLockGuard<NTtyData> {
|
||
self.data.lock_irqsave()
|
||
}
|
||
|
||
#[inline]
|
||
pub fn disc_data_try_lock(&self) -> Result<SpinLockGuard<NTtyData>, SystemError> {
|
||
self.data.try_lock_irqsave()
|
||
}
|
||
|
||
fn ioctl_helper(&self, tty: Arc<TtyCore>, cmd: u32, arg: usize) -> Result<usize, SystemError> {
|
||
match cmd {
|
||
TtyIoctlCmd::TCXONC => {
|
||
todo!()
|
||
}
|
||
TtyIoctlCmd::TCFLSH => {
|
||
todo!()
|
||
}
|
||
_ => {
|
||
return TtyCore::tty_mode_ioctl(tty.clone(), cmd, arg);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
#[derive(Debug)]
|
||
pub struct NTtyData {
|
||
/// 写者管理,tty只有一个写者,即ttydevice,所以不需要加锁
|
||
/// 读取缓冲区的头指针,表示下一个将要接受进buf的字符的位置
|
||
read_head: usize,
|
||
/// 提交缓冲区的头指针,用于行规程处理
|
||
commit_head: usize,
|
||
/// 规范缓冲区的头指针,用于规范模式的处理
|
||
canon_head: usize,
|
||
/// 回显缓冲区的头指针,用于存储需要回显的字符
|
||
echo_head: usize,
|
||
/// 回显过程中用于提交的头指针
|
||
echo_commit: usize,
|
||
/// 标记回显字符的起始位置
|
||
echo_mark: usize,
|
||
|
||
/// 读者管理
|
||
/// 读取字符的尾指针,即当前读取位置
|
||
read_tail: usize,
|
||
/// 行的起始位置
|
||
line_start: usize,
|
||
/// 预读字符数,用于处理控制字符
|
||
lookahead_count: usize,
|
||
|
||
// 更改以下六个标记时必须持有termios的锁
|
||
/// Line-next 标志,表示下一个输入字符应当按字面处理
|
||
lnext: bool,
|
||
/// 擦除状态的标志
|
||
erasing: bool,
|
||
/// Raw 模式的标志
|
||
raw: bool,
|
||
/// Real raw 模式的标志
|
||
real_raw: bool,
|
||
/// 规范模式的标志
|
||
icanon: bool,
|
||
/// 是否开启echo
|
||
echo: bool,
|
||
/// 标志是否正在进行推送
|
||
pushing: bool,
|
||
/// 是否没有空间可写
|
||
no_room: bool,
|
||
|
||
/// 光标所在列
|
||
cursor_column: u32,
|
||
/// 规范模式下光标所在列
|
||
canon_cursor_column: u32,
|
||
/// 回显缓冲区的尾指针
|
||
echo_tail: usize,
|
||
|
||
/// 写者与读者共享
|
||
read_buf: [u8; NTTY_BUFSIZE],
|
||
echo_buf: [u8; NTTY_BUFSIZE],
|
||
|
||
read_flags: StaticBitmap<NTTY_BUFSIZE>,
|
||
char_map: StaticBitmap<256>,
|
||
|
||
tty: Weak<TtyCore>,
|
||
}
|
||
|
||
impl NTtyData {
|
||
pub fn new() -> Self {
|
||
Self {
|
||
read_head: 0,
|
||
commit_head: 0,
|
||
canon_head: 0,
|
||
echo_head: 0,
|
||
echo_commit: 0,
|
||
echo_mark: 0,
|
||
read_tail: 0,
|
||
line_start: 0,
|
||
lookahead_count: 0,
|
||
lnext: false,
|
||
erasing: false,
|
||
raw: false,
|
||
real_raw: false,
|
||
icanon: false,
|
||
pushing: false,
|
||
echo: false,
|
||
cursor_column: 0,
|
||
canon_cursor_column: 0,
|
||
echo_tail: 0,
|
||
read_buf: [0; NTTY_BUFSIZE],
|
||
echo_buf: [0; NTTY_BUFSIZE],
|
||
read_flags: StaticBitmap::new(),
|
||
char_map: StaticBitmap::new(),
|
||
tty: Weak::default(),
|
||
no_room: false,
|
||
}
|
||
}
|
||
|
||
#[inline]
|
||
pub fn read_cnt(&self) -> usize {
|
||
self.read_head - self.read_tail
|
||
}
|
||
|
||
#[inline]
|
||
pub fn read_at(&self, i: usize) -> u8 {
|
||
let i = i & (NTTY_BUFSIZE - 1);
|
||
self.read_buf[i]
|
||
}
|
||
|
||
/// ### 接收数据到NTTY
|
||
pub fn receive_buf_common(
|
||
&mut self,
|
||
tty: Arc<TtyCore>,
|
||
buf: &[u8],
|
||
flags: Option<&[u8]>,
|
||
mut count: usize,
|
||
flow: bool,
|
||
) -> Result<usize, SystemError> {
|
||
// 获取termios读锁
|
||
let termios = tty.core().termios();
|
||
let mut overflow;
|
||
let mut n;
|
||
let mut offset = 0;
|
||
let mut recved = 0;
|
||
loop {
|
||
let tail = self.read_tail;
|
||
|
||
let mut room = NTTY_BUFSIZE - (self.read_head - tail);
|
||
if termios.input_mode.contains(InputMode::PARMRK) {
|
||
room = (room + 2) / 3;
|
||
}
|
||
|
||
room -= 1;
|
||
if room == 0 || room > NTTY_BUFSIZE {
|
||
// 可能溢出
|
||
overflow = self.icanon && self.canon_head == tail;
|
||
if room > NTTY_BUFSIZE && overflow {
|
||
self.read_head -= 1;
|
||
}
|
||
self.no_room = flow && !overflow;
|
||
room = if overflow { !0 } else { 0 }
|
||
} else {
|
||
overflow = false;
|
||
}
|
||
|
||
n = count.min(room);
|
||
if n == 0 {
|
||
break;
|
||
}
|
||
|
||
if !overflow {
|
||
if let Some(flags) = flags {
|
||
self.receive_buf(tty.clone(), &buf[offset..], Some(&flags[offset..]), n);
|
||
} else {
|
||
self.receive_buf(tty.clone(), &buf[offset..], flags, n);
|
||
}
|
||
}
|
||
|
||
offset += n;
|
||
|
||
count -= n;
|
||
|
||
recved += n;
|
||
|
||
if tty.core().flags().contains(TtyFlag::LDISC_CHANGING) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
// TODO: throttle
|
||
|
||
Ok(recved)
|
||
}
|
||
|
||
pub fn receive_buf(
|
||
&mut self,
|
||
tty: Arc<TtyCore>,
|
||
buf: &[u8],
|
||
flags: Option<&[u8]>,
|
||
count: usize,
|
||
) {
|
||
let termios = tty.core().termios();
|
||
let preops = termios.input_mode.contains(InputMode::ISTRIP)
|
||
|| termios.input_mode.contains(InputMode::IUCLC)
|
||
|| termios.local_mode.contains(LocalMode::IEXTEN);
|
||
|
||
let look_ahead = self.lookahead_count.min(count);
|
||
if self.real_raw {
|
||
self.receive_buf_real_raw(buf, count);
|
||
} else if self.raw || (termios.local_mode.contains(LocalMode::EXTPROC) && !preops) {
|
||
self.receive_buf_raw(buf, flags, count);
|
||
} else if tty.core().is_closing() && !termios.local_mode.contains(LocalMode::EXTPROC) {
|
||
todo!()
|
||
} else {
|
||
if look_ahead > 0 {
|
||
self.receive_buf_standard(tty.clone(), buf, flags, look_ahead, true);
|
||
}
|
||
|
||
if count > look_ahead {
|
||
self.receive_buf_standard(tty.clone(), buf, flags, count - look_ahead, false);
|
||
}
|
||
|
||
// 刷新echo
|
||
self.flush_echoes(tty.clone());
|
||
|
||
tty.flush_chars(tty.core());
|
||
}
|
||
|
||
self.lookahead_count -= look_ahead;
|
||
|
||
if self.icanon && !termios.local_mode.contains(LocalMode::EXTPROC) {
|
||
return;
|
||
}
|
||
|
||
self.commit_head = self.read_head;
|
||
|
||
if self.read_cnt() > 0 {
|
||
tty.core()
|
||
.read_wq()
|
||
.wakeup_any((EPollEventType::EPOLLIN | EPollEventType::EPOLLRDBAND).bits() as u64);
|
||
}
|
||
}
|
||
|
||
fn receive_buf_real_raw(&mut self, buf: &[u8], mut count: usize) {
|
||
let mut head = ntty_buf_mask(self.read_head);
|
||
let mut n = count.min(NTTY_BUFSIZE - head);
|
||
|
||
// 假如有一部分在队列头部,则这部分是拷贝尾部部分
|
||
self.read_buf[head..(head + n)].copy_from_slice(&buf[0..n]);
|
||
self.read_head += n;
|
||
count -= n;
|
||
let offset = n;
|
||
|
||
// 假如有一部分在队列头部,则这部分是拷贝头部部分
|
||
head = ntty_buf_mask(self.read_head);
|
||
n = count.min(NTTY_BUFSIZE - head);
|
||
self.read_buf[head..(head + n)].copy_from_slice(&buf[offset..(offset + n)]);
|
||
self.read_head += n;
|
||
}
|
||
|
||
fn receive_buf_raw(&mut self, buf: &[u8], flags: Option<&[u8]>, mut count: usize) {
|
||
// TTY_NORMAL 目前这部分未做,所以先占位置而不做抽象
|
||
let mut flag = 1;
|
||
let mut f_offset = 0;
|
||
let mut c_offset = 0;
|
||
while count != 0 {
|
||
if flags.is_some() {
|
||
flag = flags.as_ref().unwrap()[f_offset];
|
||
f_offset += 1;
|
||
}
|
||
|
||
if likely(flag == 1) {
|
||
self.read_buf[self.read_head] = buf[c_offset];
|
||
c_offset += 1;
|
||
self.read_head += 1;
|
||
} else {
|
||
todo!()
|
||
}
|
||
|
||
count -= 1;
|
||
}
|
||
}
|
||
|
||
pub fn flush_echoes(&mut self, tty: Arc<TtyCore>) {
|
||
let termios = tty.core().termios();
|
||
if !termios.local_mode.contains(LocalMode::ECHO)
|
||
&& !termios.local_mode.contains(LocalMode::ECHONL)
|
||
|| self.echo_commit == self.echo_head
|
||
{
|
||
return;
|
||
}
|
||
|
||
self.echo_commit = self.echo_head;
|
||
drop(termios);
|
||
let _ = self.echoes(tty);
|
||
}
|
||
|
||
pub fn receive_buf_standard(
|
||
&mut self,
|
||
tty: Arc<TtyCore>,
|
||
buf: &[u8],
|
||
flags: Option<&[u8]>,
|
||
mut count: usize,
|
||
lookahead_done: bool,
|
||
) {
|
||
let termios = tty.core().termios();
|
||
if flags.is_some() {
|
||
todo!("ntty recv buf flags todo");
|
||
}
|
||
|
||
let mut offset = 0;
|
||
while count > 0 {
|
||
if offset >= buf.len() {
|
||
break;
|
||
}
|
||
let mut c = buf[offset];
|
||
offset += 1;
|
||
|
||
if self.lnext {
|
||
// 将下一个字符当做字面值处理
|
||
self.lnext = false;
|
||
if termios.input_mode.contains(InputMode::ISTRIP) {
|
||
c &= 0x7f;
|
||
}
|
||
|
||
if termios.input_mode.contains(InputMode::IUCLC)
|
||
&& termios.local_mode.contains(LocalMode::IEXTEN)
|
||
{
|
||
c = (c as char).to_ascii_lowercase() as u8;
|
||
self.receive_char(c, tty.clone())
|
||
}
|
||
|
||
continue;
|
||
}
|
||
|
||
if termios.input_mode.contains(InputMode::ISTRIP) {
|
||
c &= 0x7f;
|
||
}
|
||
|
||
if termios.input_mode.contains(InputMode::IUCLC)
|
||
&& termios.local_mode.contains(LocalMode::IEXTEN)
|
||
{
|
||
c = (c as char).to_ascii_lowercase() as u8;
|
||
}
|
||
|
||
if termios.local_mode.contains(LocalMode::EXTPROC) {
|
||
self.add_read_byte(c);
|
||
continue;
|
||
}
|
||
|
||
if ((c as usize) < self.char_map.size()) && self.char_map.get(c as usize).unwrap() {
|
||
// 特殊字符
|
||
self.receive_special_char(c, tty.clone(), lookahead_done);
|
||
} else {
|
||
self.receive_char(c, tty.clone());
|
||
}
|
||
|
||
count -= 1;
|
||
}
|
||
}
|
||
|
||
#[inline(never)]
|
||
pub fn receive_special_char(&mut self, mut c: u8, tty: Arc<TtyCore>, lookahead_done: bool) {
|
||
let is_flow_ctrl = self.is_flow_ctrl_char(tty.clone(), c, lookahead_done);
|
||
let termios = tty.core().termios();
|
||
|
||
// 启用软件流控,并且该字符已经当做软件流控字符处理
|
||
if termios.input_mode.contains(InputMode::IXON) && is_flow_ctrl {
|
||
return;
|
||
}
|
||
|
||
if termios.local_mode.contains(LocalMode::ISIG) {
|
||
if c == termios.control_characters[ControlCharIndex::VINTR] {
|
||
self.recv_sig_char(tty.clone(), &termios, Signal::SIGINT, c);
|
||
return;
|
||
}
|
||
|
||
if c == termios.control_characters[ControlCharIndex::VQUIT] {
|
||
self.recv_sig_char(tty.clone(), &termios, Signal::SIGQUIT, c);
|
||
return;
|
||
}
|
||
|
||
if c == termios.control_characters[ControlCharIndex::VSUSP] {
|
||
self.recv_sig_char(tty.clone(), &termios, Signal::SIGTSTP, c);
|
||
return;
|
||
}
|
||
}
|
||
|
||
let flow = tty.core().flow_irqsave();
|
||
if flow.stopped
|
||
&& !flow.tco_stopped
|
||
&& termios.input_mode.contains(InputMode::IXON)
|
||
&& termios.input_mode.contains(InputMode::IXANY)
|
||
{
|
||
tty.tty_start();
|
||
self.process_echoes(tty.clone());
|
||
}
|
||
drop(flow);
|
||
|
||
if c == b'\r' {
|
||
if termios.input_mode.contains(InputMode::IGNCR) {
|
||
// 忽略
|
||
return;
|
||
}
|
||
if termios.input_mode.contains(InputMode::ICRNL) {
|
||
// 映射为换行
|
||
c = b'\n';
|
||
}
|
||
} else if c == b'\n' && termios.input_mode.contains(InputMode::INLCR) {
|
||
// 映射为回车
|
||
c = b'\r';
|
||
}
|
||
|
||
if self.icanon {
|
||
if c == termios.control_characters[ControlCharIndex::VERASE]
|
||
|| c == termios.control_characters[ControlCharIndex::VKILL]
|
||
|| (c == termios.control_characters[ControlCharIndex::VWERASE]
|
||
&& termios.local_mode.contains(LocalMode::IEXTEN))
|
||
{
|
||
self.eraser(c, &termios);
|
||
self.commit_echoes(tty.clone());
|
||
return;
|
||
}
|
||
if c == termios.control_characters[ControlCharIndex::VLNEXT]
|
||
&& termios.local_mode.contains(LocalMode::IEXTEN)
|
||
{
|
||
self.lnext = true;
|
||
if termios.local_mode.contains(LocalMode::ECHO) {
|
||
self.finish_erasing();
|
||
if termios.local_mode.contains(LocalMode::ECHOCTL) {
|
||
self.echo_char_raw(b'^');
|
||
self.echo_char_raw(8);
|
||
self.commit_echoes(tty.clone());
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
if c == termios.control_characters[ControlCharIndex::VREPRINT]
|
||
&& termios.local_mode.contains(LocalMode::ECHO)
|
||
&& termios.local_mode.contains(LocalMode::IEXTEN)
|
||
{
|
||
let mut tail = self.canon_head;
|
||
self.finish_erasing();
|
||
self.echo_char(c, &termios);
|
||
self.echo_char_raw(b'\n');
|
||
while ntty_buf_mask(tail) != ntty_buf_mask(self.read_head) {
|
||
self.echo_char(self.read_buf[ntty_buf_mask(tail)], &termios);
|
||
tail += 1;
|
||
}
|
||
self.commit_echoes(tty.clone());
|
||
return;
|
||
}
|
||
|
||
if c == b'\n' {
|
||
if termios.local_mode.contains(LocalMode::ECHO)
|
||
|| termios.local_mode.contains(LocalMode::ECHONL)
|
||
{
|
||
self.echo_char_raw(b'\n');
|
||
self.commit_echoes(tty.clone());
|
||
}
|
||
|
||
self.read_flags.set(ntty_buf_mask(self.read_head), true);
|
||
self.read_buf[ntty_buf_mask(self.read_head)] = c;
|
||
self.read_head += 1;
|
||
self.canon_head = self.read_head;
|
||
tty.core().read_wq().wakeup_any(
|
||
(EPollEventType::EPOLLIN | EPollEventType::EPOLLRDNORM).bits() as u64,
|
||
);
|
||
return;
|
||
}
|
||
|
||
if c == termios.control_characters[ControlCharIndex::VEOF] {
|
||
c = ControlCharIndex::DISABLE_CHAR;
|
||
|
||
self.read_flags.set(ntty_buf_mask(self.read_head), true);
|
||
self.read_buf[ntty_buf_mask(self.read_head)] = c;
|
||
self.read_head += 1;
|
||
self.canon_head = self.read_head;
|
||
tty.core().read_wq().wakeup_any(
|
||
(EPollEventType::EPOLLIN | EPollEventType::EPOLLRDNORM).bits() as u64,
|
||
);
|
||
return;
|
||
}
|
||
|
||
if c == termios.control_characters[ControlCharIndex::VEOL]
|
||
|| (c == termios.control_characters[ControlCharIndex::VEOL2]
|
||
&& termios.local_mode.contains(LocalMode::IEXTEN))
|
||
{
|
||
if termios.local_mode.contains(LocalMode::ECHO) {
|
||
if self.canon_head == self.read_head {
|
||
self.add_echo_byte(EchoOperation::Start.to_u8());
|
||
self.add_echo_byte(EchoOperation::SetCanonCol.to_u8());
|
||
}
|
||
self.echo_char(c, &termios);
|
||
self.commit_echoes(tty.clone());
|
||
}
|
||
|
||
if c == 0o377 && termios.input_mode.contains(InputMode::PARMRK) {
|
||
self.read_buf[ntty_buf_mask(self.read_head)] = c;
|
||
self.read_head += 1;
|
||
}
|
||
|
||
self.read_flags.set(ntty_buf_mask(self.read_head), true);
|
||
self.read_buf[ntty_buf_mask(self.read_head)] = c;
|
||
self.read_head += 1;
|
||
self.canon_head = self.read_head;
|
||
tty.core().read_wq().wakeup_any(
|
||
(EPollEventType::EPOLLIN | EPollEventType::EPOLLRDNORM).bits() as u64,
|
||
);
|
||
return;
|
||
}
|
||
}
|
||
|
||
if termios.local_mode.contains(LocalMode::ECHO) {
|
||
self.finish_erasing();
|
||
if c == b'\n' {
|
||
self.echo_char_raw(b'\n');
|
||
} else {
|
||
if self.canon_head == self.read_head {
|
||
self.add_echo_byte(EchoOperation::Start.to_u8());
|
||
self.add_echo_byte(EchoOperation::SetCanonCol.to_u8());
|
||
}
|
||
self.echo_char(c, &termios);
|
||
}
|
||
|
||
self.commit_echoes(tty.clone());
|
||
}
|
||
|
||
if c == 0o377 && termios.input_mode.contains(InputMode::PARMRK) {
|
||
self.read_buf[ntty_buf_mask(self.read_head)] = c;
|
||
self.read_head += 1;
|
||
}
|
||
|
||
self.read_buf[ntty_buf_mask(self.read_head)] = c;
|
||
self.read_head += 1;
|
||
}
|
||
|
||
/// ## ntty默认eraser function
|
||
#[inline(never)]
|
||
fn eraser(&mut self, mut c: u8, termios: &RwLockReadGuard<Termios>) {
|
||
if self.read_head == self.canon_head {
|
||
return;
|
||
}
|
||
|
||
let erase = c == termios.control_characters[ControlCharIndex::VERASE];
|
||
let werase = c == termios.control_characters[ControlCharIndex::VWERASE];
|
||
let kill = !erase && !werase;
|
||
|
||
if kill {
|
||
if !termios.local_mode.contains(LocalMode::ECHO) {
|
||
self.read_head = self.canon_head;
|
||
return;
|
||
}
|
||
if !termios.local_mode.contains(LocalMode::ECHOK)
|
||
|| !termios.local_mode.contains(LocalMode::ECHOKE)
|
||
|| !termios.local_mode.contains(LocalMode::ECHOE)
|
||
{
|
||
self.read_head = self.canon_head;
|
||
if self.erasing {
|
||
self.echo_char_raw(c);
|
||
self.erasing = false;
|
||
}
|
||
self.echo_char(c, termios);
|
||
|
||
if termios.local_mode.contains(LocalMode::ECHOK) {
|
||
// 添加新行
|
||
self.echo_char_raw(b'\n');
|
||
}
|
||
return;
|
||
}
|
||
}
|
||
|
||
let mut head;
|
||
let mut cnt;
|
||
while ntty_buf_mask(self.read_head) != ntty_buf_mask(self.canon_head) {
|
||
head = self.read_head;
|
||
|
||
loop {
|
||
// 消除多字节字符
|
||
head -= 1;
|
||
c = self.read_buf[ntty_buf_mask(head)];
|
||
|
||
if !(Self::is_continuation(c, termios)
|
||
&& ntty_buf_mask(head) != ntty_buf_mask(self.canon_head))
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
|
||
if Self::is_continuation(c, termios) {
|
||
break;
|
||
}
|
||
|
||
if werase {
|
||
todo!()
|
||
}
|
||
|
||
cnt = self.read_head - head;
|
||
self.read_head = head;
|
||
if termios.local_mode.contains(LocalMode::ECHO) {
|
||
if termios.local_mode.contains(LocalMode::ECHOPRT) {
|
||
if !self.erasing {
|
||
self.echo_char_raw(b'\\');
|
||
self.erasing = true;
|
||
}
|
||
self.echo_char(c, termios);
|
||
cnt -= 1;
|
||
while cnt > 0 {
|
||
cnt -= 1;
|
||
head += 1;
|
||
self.echo_char_raw(self.read_buf[ntty_buf_mask(head)]);
|
||
self.add_echo_byte(EchoOperation::Start.to_u8());
|
||
self.add_echo_byte(EchoOperation::MoveBackCol.to_u8());
|
||
}
|
||
} else if erase && !termios.local_mode.contains(LocalMode::ECHOE) {
|
||
self.echo_char(
|
||
termios.control_characters[ControlCharIndex::VERASE],
|
||
termios,
|
||
);
|
||
} else if c == b'\t' {
|
||
let mut num_chars = 0;
|
||
let mut after_tab = false;
|
||
let mut tail = self.read_head;
|
||
|
||
while ntty_buf_mask(tail) != ntty_buf_mask(self.canon_head) {
|
||
tail -= 1;
|
||
c = self.read_buf[ntty_buf_mask(tail)];
|
||
if c == b'\t' {
|
||
after_tab = true;
|
||
break;
|
||
} else if (c as char).is_control() {
|
||
if termios.local_mode.contains(LocalMode::ECHOCTL) {
|
||
num_chars += 2;
|
||
}
|
||
} else if !Self::is_continuation(c, termios) {
|
||
num_chars += 1;
|
||
}
|
||
}
|
||
|
||
self.echo_erase_tab(num_chars, after_tab);
|
||
} else {
|
||
if (c as char).is_control() && termios.local_mode.contains(LocalMode::ECHOCTL) {
|
||
// 8 => '\b'
|
||
self.echo_char_raw(8);
|
||
self.echo_char_raw(b' ');
|
||
self.echo_char_raw(8);
|
||
}
|
||
|
||
if !(c as char).is_control() || termios.local_mode.contains(LocalMode::ECHOCTL)
|
||
{
|
||
// 8 => '\b'
|
||
self.echo_char_raw(8);
|
||
self.echo_char_raw(b' ');
|
||
self.echo_char_raw(8);
|
||
}
|
||
}
|
||
}
|
||
|
||
if erase {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if self.read_head == self.canon_head && termios.local_mode.contains(LocalMode::ECHO) {
|
||
self.finish_erasing();
|
||
}
|
||
}
|
||
|
||
fn finish_erasing(&mut self) {
|
||
if self.erasing {
|
||
self.echo_char_raw(b'/');
|
||
self.erasing = false;
|
||
}
|
||
}
|
||
|
||
fn echo_erase_tab(&mut self, mut num: u8, after_tab: bool) {
|
||
self.add_echo_byte(EchoOperation::Start.to_u8());
|
||
self.add_echo_byte(EchoOperation::EraseTab.to_u8());
|
||
|
||
num &= 7;
|
||
|
||
if after_tab {
|
||
num |= 0x80;
|
||
}
|
||
|
||
self.add_echo_byte(num);
|
||
}
|
||
|
||
/// ## 多字节字符检测
|
||
/// 检测是否为多字节字符的后续字节
|
||
fn is_continuation(c: u8, termios: &RwLockReadGuard<Termios>) -> bool {
|
||
return termios.input_mode.contains(InputMode::IUTF8) && (c & 0xc0) == 0x80;
|
||
}
|
||
|
||
/// ## 该字符是否已经当做流控字符处理
|
||
pub fn is_flow_ctrl_char(&mut self, tty: Arc<TtyCore>, c: u8, lookahead_done: bool) -> bool {
|
||
let termios = tty.core().termios();
|
||
|
||
if !(termios.control_characters[ControlCharIndex::VSTART] == c
|
||
|| termios.control_characters[ControlCharIndex::VSTOP] == c)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
if lookahead_done {
|
||
return true;
|
||
}
|
||
|
||
if termios.control_characters[ControlCharIndex::VSTART] == c {
|
||
tty.tty_start();
|
||
self.process_echoes(tty.clone());
|
||
return true;
|
||
} else {
|
||
tty.tty_stop();
|
||
return true;
|
||
}
|
||
}
|
||
|
||
/// ## 接收到信号字符时的处理
|
||
fn recv_sig_char(
|
||
&mut self,
|
||
tty: Arc<TtyCore>,
|
||
termios: &RwLockReadGuard<Termios>,
|
||
signal: Signal,
|
||
c: u8,
|
||
) {
|
||
self.input_signal(tty.clone(), termios, signal);
|
||
if termios.input_mode.contains(InputMode::IXON) {
|
||
tty.tty_start();
|
||
}
|
||
|
||
if termios.local_mode.contains(LocalMode::ECHO) {
|
||
self.echo_char(c, termios);
|
||
self.commit_echoes(tty);
|
||
} else {
|
||
self.process_echoes(tty);
|
||
}
|
||
}
|
||
|
||
/// ## 处理输入信号
|
||
pub fn input_signal(
|
||
&mut self,
|
||
tty: Arc<TtyCore>,
|
||
termios: &RwLockReadGuard<Termios>,
|
||
signal: Signal,
|
||
) {
|
||
// 先处理信号
|
||
let ctrl_info = tty.core().contorl_info_irqsave();
|
||
let pg = ctrl_info.pgid;
|
||
if let Some(pg) = pg {
|
||
let _ = Syscall::kill(pg, signal as i32);
|
||
}
|
||
|
||
if !termios.local_mode.contains(LocalMode::NOFLSH) {
|
||
// 重置
|
||
self.echo_head = 0;
|
||
self.echo_tail = 0;
|
||
self.echo_mark = 0;
|
||
self.echo_commit = 0;
|
||
|
||
let _ = tty.flush_buffer(tty.core());
|
||
|
||
self.read_head = 0;
|
||
self.canon_head = 0;
|
||
self.read_tail = 0;
|
||
self.line_start = 0;
|
||
|
||
self.erasing = false;
|
||
self.read_flags.set_all(false);
|
||
self.pushing = false;
|
||
self.lookahead_count = 0;
|
||
|
||
if tty.core().link().is_some() {
|
||
self.packet_mode_flush(tty.core());
|
||
}
|
||
}
|
||
}
|
||
|
||
pub fn receive_char(&mut self, c: u8, tty: Arc<TtyCore>) {
|
||
let termios = tty.core().termios();
|
||
|
||
if termios.local_mode.contains(LocalMode::ECHO) {
|
||
if self.erasing {
|
||
self.add_echo_byte(b'/');
|
||
self.erasing = false;
|
||
}
|
||
|
||
if self.canon_head == self.read_head {
|
||
self.add_echo_byte(EchoOperation::Start.to_u8());
|
||
self.add_echo_byte(EchoOperation::SetCanonCol.to_u8());
|
||
}
|
||
|
||
self.echo_char(c, &termios);
|
||
self.commit_echoes(tty.clone());
|
||
}
|
||
|
||
if c == 0o377 && tty.core().termios().input_mode.contains(InputMode::PARMRK) {
|
||
self.add_read_byte(c);
|
||
}
|
||
self.add_read_byte(c);
|
||
}
|
||
|
||
pub fn echo_char(&mut self, c: u8, termios: &RwLockReadGuard<Termios>) {
|
||
if c == EchoOperation::Start.to_u8() {
|
||
self.add_echo_byte(EchoOperation::Start.to_u8());
|
||
self.add_echo_byte(EchoOperation::Start.to_u8());
|
||
} else {
|
||
if termios.local_mode.contains(LocalMode::ECHOCTL)
|
||
&& (c as char).is_control()
|
||
&& c != b'\t'
|
||
{
|
||
self.add_echo_byte(EchoOperation::Start.to_u8());
|
||
}
|
||
self.add_echo_byte(c);
|
||
}
|
||
}
|
||
|
||
pub fn echo_char_raw(&mut self, c: u8) {
|
||
if c == EchoOperation::Start.to_u8() {
|
||
self.add_echo_byte(EchoOperation::Start.to_u8());
|
||
self.add_echo_byte(EchoOperation::Start.to_u8());
|
||
} else {
|
||
self.add_echo_byte(c);
|
||
}
|
||
}
|
||
|
||
/// ## 提交echobuf里的数据显示
|
||
pub fn commit_echoes(&mut self, tty: Arc<TtyCore>) {
|
||
let head = self.echo_head;
|
||
self.echo_mark = head;
|
||
let old = self.echo_commit - self.echo_tail;
|
||
|
||
// 需要echo的字符个数
|
||
let nr = head - self.echo_tail;
|
||
|
||
if nr < ECHO_COMMIT_WATERMARK || nr % ECHO_BLOCK > old % ECHO_BLOCK {
|
||
return;
|
||
}
|
||
|
||
self.echo_commit = head;
|
||
let echoed = self.echoes(tty.clone());
|
||
|
||
if echoed.is_ok() && echoed.unwrap() > 0 {
|
||
tty.flush_chars(tty.core());
|
||
}
|
||
}
|
||
|
||
pub fn add_echo_byte(&mut self, c: u8) {
|
||
self.echo_buf[ntty_buf_mask(self.echo_head)] = c;
|
||
self.echo_head += 1;
|
||
}
|
||
|
||
pub fn add_read_byte(&mut self, c: u8) {
|
||
self.read_buf[ntty_buf_mask(self.read_head)] = c;
|
||
self.read_head += 1;
|
||
}
|
||
|
||
/// ### 将read_buffer的部分值置0
|
||
///
|
||
/// 只会在规范模式和禁用echo下执行
|
||
#[inline]
|
||
pub fn zero_buffer(&mut self, offset: usize, size: usize) {
|
||
let offset = offset & (NTTY_BUFSIZE - 1);
|
||
if self.icanon && !self.echo {
|
||
let n = offset + size;
|
||
if n > NTTY_BUFSIZE {
|
||
for c in &mut self.read_buf[offset..NTTY_BUFSIZE] {
|
||
*c = 0
|
||
}
|
||
|
||
for c in &mut self.read_buf[0..(n - NTTY_BUFSIZE)] {
|
||
*c = 0
|
||
}
|
||
} else {
|
||
for c in &mut self.read_buf[offset..n] {
|
||
*c = 0
|
||
}
|
||
};
|
||
}
|
||
}
|
||
|
||
/// ## 从ntty中拷贝数据
|
||
///
|
||
/// ### 参数
|
||
///
|
||
/// ### to: 存储数据
|
||
/// ### tail: 读取尾
|
||
pub fn ntty_copy(
|
||
&mut self,
|
||
to: &mut [u8],
|
||
tail: usize,
|
||
n: &mut usize,
|
||
) -> Result<(), SystemError> {
|
||
if to.len() < *n {
|
||
*n = to.len();
|
||
// return Err(SystemError::EINVAL);
|
||
}
|
||
if tail > NTTY_BUFSIZE {
|
||
return Err(SystemError::EINVAL);
|
||
}
|
||
|
||
let size = NTTY_BUFSIZE - tail;
|
||
|
||
if size < *n {
|
||
// 有一部分数据在头部,则先拷贝后面部分,再拷贝头部
|
||
// TODO: tty审计?
|
||
to[0..size].copy_from_slice(&self.read_buf[tail..(tail + size)]);
|
||
to[size..(*n)].copy_from_slice(&self.read_buf[0..(*n - size)]);
|
||
} else {
|
||
to[..*n].copy_from_slice(&self.read_buf[tail..(tail + *n)])
|
||
}
|
||
|
||
self.zero_buffer(tail, *n);
|
||
|
||
Ok(())
|
||
}
|
||
|
||
/// ## 规范模式下跳过EOF
|
||
pub fn canon_skip_eof(&mut self) {
|
||
// 没有数据
|
||
if self.read_tail == self.canon_head {
|
||
return;
|
||
}
|
||
|
||
let tail = self.read_tail & (NTTY_BUFSIZE - 1);
|
||
|
||
// 查看read_flags是否读取位置为特殊字符
|
||
if !self.read_flags.get(tail).unwrap() {
|
||
return;
|
||
}
|
||
|
||
// 确保读取位置是'\0'字符
|
||
if self.read_buf[tail] != ControlCharIndex::DISABLE_CHAR {
|
||
return;
|
||
}
|
||
|
||
// 处理该字符,将read_flagsw该位清除
|
||
self.read_flags.set(tail, false);
|
||
// 读取位置+1,即跳过该字符不做处理
|
||
self.read_tail += 1;
|
||
}
|
||
|
||
/// ## 在规范模式(canonical mode)下从读缓冲中复制一行
|
||
///
|
||
/// 一次只拷贝一行
|
||
///
|
||
/// ## 参数
|
||
/// ### dst: 存放数据
|
||
/// ### nr: 需要拷贝的数据大小
|
||
///
|
||
/// ## 返回值
|
||
/// ### true: 表示一行未结束并且还有数据可读
|
||
/// ### false: 一行已结束或者没有数据可读
|
||
pub fn canon_copy_from_read_buf(
|
||
&mut self,
|
||
dst: &mut [u8],
|
||
nr: &mut usize,
|
||
offset: &mut usize,
|
||
) -> Result<bool, SystemError> {
|
||
if *nr == 0 {
|
||
return Ok(false);
|
||
}
|
||
|
||
let canon_head = self.canon_head;
|
||
|
||
// 取得能够读到的字符数,即canon_head - self.read_tail和nr最小值
|
||
let mut n = (*nr).min(canon_head - self.read_tail);
|
||
|
||
// 获得读尾index
|
||
let tail = self.read_tail & (NTTY_BUFSIZE - 1);
|
||
|
||
// 避免越界,这个size才是实际读取大小
|
||
let size = if tail + n > NTTY_BUFSIZE {
|
||
NTTY_BUFSIZE
|
||
} else {
|
||
tail + n
|
||
};
|
||
|
||
// 找到eol的坐标
|
||
let tmp = self.read_flags.next_index(tail);
|
||
// 找到的话即为坐标,未找到的话即为NTTY_BUFSIZE
|
||
let mut eol = if let Some(tmp) = tmp { tmp } else { size };
|
||
if eol > size {
|
||
eol = size
|
||
}
|
||
|
||
// 是否需要绕回缓冲区头部
|
||
let more = n - (size - tail);
|
||
|
||
// 是否找到eol
|
||
let found = if eol == NTTY_BUFSIZE && more > 0 {
|
||
// 需要返回头部
|
||
let ret = self.read_flags.first_index();
|
||
if let Some(tmp) = ret {
|
||
// 在头部范围内找到eol
|
||
if tmp < more {
|
||
eol = tmp;
|
||
}
|
||
} else {
|
||
eol = more;
|
||
}
|
||
eol != more
|
||
} else {
|
||
// 不需要返回头部
|
||
eol != size
|
||
};
|
||
|
||
n = eol - tail;
|
||
if n > NTTY_BUFSIZE {
|
||
// 减法溢出则加上BUFSIZE即可限制在0-NTTY_BUFSIZE内
|
||
n += NTTY_BUFSIZE;
|
||
}
|
||
|
||
// 规范模式下实际扫描过的字符数,需要将eol计算在内
|
||
let count = if found { n + 1 } else { n };
|
||
|
||
// 表示这一行未结束
|
||
if !found || self.read_at(eol) != ControlCharIndex::DISABLE_CHAR {
|
||
n = count;
|
||
}
|
||
|
||
self.ntty_copy(&mut dst[*offset..], tail, &mut n)?;
|
||
*nr -= n;
|
||
*offset += n;
|
||
|
||
if found {
|
||
self.read_flags.set(eol, false);
|
||
}
|
||
|
||
self.read_tail += count;
|
||
|
||
if found {
|
||
if !self.pushing {
|
||
self.line_start = self.read_tail;
|
||
} else {
|
||
self.pushing = false;
|
||
}
|
||
|
||
// todo: 审计?
|
||
return Ok(false);
|
||
}
|
||
|
||
// 这里是表示没有找到eol,根据是否还有数据可读返回
|
||
Ok(self.read_tail != canon_head)
|
||
}
|
||
|
||
/// ## 根据终端的模式和输入缓冲区中的数据量,判断是否可读字符
|
||
pub fn input_available(&self, termios: RwLockReadGuard<Termios>, poll: bool) -> bool {
|
||
// 计算最小字符数
|
||
let amt = if poll
|
||
&& termios.control_characters[ControlCharIndex::VTIME] as u32 == 0
|
||
&& termios.control_characters[ControlCharIndex::VMIN] as u32 != 0
|
||
{
|
||
termios.control_characters[ControlCharIndex::VMIN] as usize
|
||
} else {
|
||
1
|
||
};
|
||
|
||
// 规范模式且非拓展
|
||
if self.icanon && !termios.local_mode.contains(LocalMode::EXTPROC) {
|
||
return self.canon_head != self.read_tail;
|
||
} else {
|
||
return (self.commit_head - self.read_tail) >= amt;
|
||
}
|
||
}
|
||
|
||
/// ## 非规范模式下从read_buf读取数据
|
||
///
|
||
/// ## 参数
|
||
/// ### termios: tty对应的termioss读锁守卫
|
||
/// ### dst: 存储读取数据
|
||
/// ### nr: 读取长度
|
||
///
|
||
/// ## 返回值
|
||
/// ### true: 还有更多数据可读
|
||
/// ### false: 无更多数据可读
|
||
pub fn copy_from_read_buf(
|
||
&mut self,
|
||
termios: RwLockReadGuard<Termios>,
|
||
dst: &mut [u8],
|
||
nr: &mut usize,
|
||
offset: &mut usize,
|
||
) -> Result<bool, SystemError> {
|
||
let head = self.commit_head;
|
||
let tail = self.read_tail & (NTTY_BUFSIZE - 1);
|
||
|
||
// 计算出可读的字符数
|
||
let mut n = (NTTY_BUFSIZE - tail).min(head - self.read_tail);
|
||
n = n.min(*nr);
|
||
|
||
if n > 0 {
|
||
// 拷贝数据
|
||
self.ntty_copy(&mut dst[*offset..], tail, &mut n)?;
|
||
// todo:审计?
|
||
self.read_tail += n;
|
||
|
||
// 是否只读取了eof
|
||
let eof =
|
||
n == 1 && self.read_buf[tail] == termios.control_characters[ControlCharIndex::VEOF];
|
||
|
||
if termios.local_mode.contains(LocalMode::EXTPROC)
|
||
&& self.icanon
|
||
&& eof
|
||
&& head == self.read_tail
|
||
{
|
||
return Ok(false);
|
||
}
|
||
|
||
*nr -= n;
|
||
*offset += n;
|
||
|
||
return Ok(head != self.read_tail);
|
||
}
|
||
|
||
Ok(false)
|
||
}
|
||
|
||
/// ## 用于处理带有 OPOST(Output Post-processing)标志的输出块的函数
|
||
/// OPOST 是 POSIX 终端驱动器标志之一,用于指定在写入终端设备之前对输出数据进行一些后期处理。
|
||
pub fn process_output_block(
|
||
&mut self,
|
||
core: &TtyCoreData,
|
||
termios: RwLockReadGuard<Termios>,
|
||
buf: &[u8],
|
||
nr: usize,
|
||
) -> Result<usize, SystemError> {
|
||
let mut nr = nr;
|
||
let tty = self.tty.upgrade().unwrap();
|
||
let space = tty.write_room(tty.core());
|
||
|
||
// 如果读取数量大于了可用空间,则取最小的为真正的写入数量
|
||
if nr > space {
|
||
nr = space
|
||
}
|
||
|
||
let mut cnt = 0;
|
||
for (i, c) in buf.iter().enumerate().take(nr) {
|
||
cnt = i;
|
||
let c = *c;
|
||
if c as usize == 8 {
|
||
// 表示退格
|
||
if self.cursor_column > 0 {
|
||
self.cursor_column -= 1;
|
||
}
|
||
continue;
|
||
}
|
||
match c as char {
|
||
'\n' => {
|
||
if termios.output_mode.contains(OutputMode::ONLRET) {
|
||
// 将回车映射为\n,即将\n换为回车
|
||
self.cursor_column = 0;
|
||
}
|
||
if termios.output_mode.contains(OutputMode::ONLCR) {
|
||
// 输出时将\n换为\r\n
|
||
break;
|
||
}
|
||
|
||
self.canon_cursor_column = self.cursor_column;
|
||
}
|
||
'\r' => {
|
||
if termios.output_mode.contains(OutputMode::ONOCR) && self.cursor_column == 0 {
|
||
// 光标已经在第0列,则不输出回车符
|
||
break;
|
||
}
|
||
|
||
if termios.output_mode.contains(OutputMode::OCRNL) {
|
||
break;
|
||
}
|
||
self.cursor_column = 0;
|
||
self.canon_cursor_column = 0;
|
||
}
|
||
'\t' => {
|
||
break;
|
||
}
|
||
_ => {
|
||
// 判断是否为控制字符
|
||
if !(c as char).is_control() {
|
||
if termios.output_mode.contains(OutputMode::OLCUC) {
|
||
break;
|
||
}
|
||
|
||
// 判断是否为utf8模式下的连续字符
|
||
if !(termios.input_mode.contains(InputMode::IUTF8)
|
||
&& (c as usize) & 0xc0 == 0x80)
|
||
{
|
||
self.cursor_column += 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
drop(termios);
|
||
return tty.write(core, buf, cnt);
|
||
}
|
||
|
||
/// ## 处理回显
|
||
pub fn process_echoes(&mut self, tty: Arc<TtyCore>) {
|
||
if self.echo_mark == self.echo_tail {
|
||
return;
|
||
}
|
||
self.echo_commit = self.echo_mark;
|
||
let echoed = self.echoes(tty.clone());
|
||
|
||
if echoed.is_ok() && echoed.unwrap() > 0 {
|
||
tty.flush_chars(tty.core());
|
||
}
|
||
}
|
||
|
||
#[inline(never)]
|
||
pub fn echoes(&mut self, tty: Arc<TtyCore>) -> Result<usize, SystemError> {
|
||
let mut space = tty.write_room(tty.core());
|
||
let ospace = space;
|
||
let termios = tty.core().termios();
|
||
let core = tty.core();
|
||
let mut tail = self.echo_tail;
|
||
|
||
while ntty_buf_mask(self.echo_commit) != ntty_buf_mask(tail) {
|
||
let c = self.echo_buf[ntty_buf_mask(tail)];
|
||
|
||
if EchoOperation::from_u8(c) == EchoOperation::Start {
|
||
if ntty_buf_mask(self.echo_commit) == ntty_buf_mask(tail + 1) {
|
||
self.echo_tail = tail;
|
||
return Ok(ospace - space);
|
||
}
|
||
|
||
// 获取到start,之后取第一个作为op
|
||
let op = EchoOperation::from_u8(self.echo_buf[ntty_buf_mask(tail + 1)]);
|
||
|
||
match op {
|
||
EchoOperation::Start => {
|
||
if space == 0 {
|
||
break;
|
||
}
|
||
|
||
if tty
|
||
.put_char(tty.core(), EchoOperation::Start.to_u8())
|
||
.is_err()
|
||
{
|
||
tty.write(core, &[EchoOperation::Start.to_u8()], 1)?;
|
||
}
|
||
|
||
self.cursor_column += 1;
|
||
space -= 1;
|
||
tail += 2;
|
||
}
|
||
EchoOperation::MoveBackCol => {
|
||
if self.cursor_column > 0 {
|
||
self.cursor_column -= 1;
|
||
}
|
||
tail += 2;
|
||
}
|
||
EchoOperation::SetCanonCol => {
|
||
self.canon_cursor_column = self.cursor_column;
|
||
tail += 2;
|
||
}
|
||
EchoOperation::EraseTab => {
|
||
if ntty_buf_mask(self.echo_commit) == ntty_buf_mask(tail + 2) {
|
||
self.echo_tail = tail;
|
||
return Ok(ospace - space);
|
||
}
|
||
|
||
// 要擦除的制表符所占用的列数
|
||
let mut char_num = self.echo_buf[ntty_buf_mask(tail + 2)] as usize;
|
||
|
||
/*
|
||
如果 num_chars 的最高位(0x80)未设置,
|
||
表示这是从输入的起始位置而不是从先前的制表符开始计算的列数。
|
||
在这种情况下,将 num_chars 与 ldata->canon_column 相加,否则,列数就是正常的制表符列数。
|
||
*/
|
||
if char_num & 0x80 == 0 {
|
||
char_num += self.canon_cursor_column as usize;
|
||
}
|
||
|
||
// 计算要回退的列数,即制表符宽度减去实际占用的列数
|
||
let mut num_bs = 8 - (char_num & 7);
|
||
if num_bs > space {
|
||
// 表示左边没有足够空间回退
|
||
break;
|
||
}
|
||
|
||
space -= num_bs;
|
||
while num_bs != 0 {
|
||
num_bs -= 1;
|
||
// 8 => '\b'
|
||
if tty.put_char(tty.core(), 8).is_err() {
|
||
tty.write(core, &[8], 1)?;
|
||
}
|
||
|
||
if self.cursor_column > 0 {
|
||
self.cursor_column -= 1;
|
||
}
|
||
}
|
||
|
||
// 已经读取了 tail tail+1 tail+2,所以这里偏移加3
|
||
tail += 3;
|
||
}
|
||
EchoOperation::Undefined(ch) => {
|
||
match ch {
|
||
8 => {
|
||
if tty.put_char(tty.core(), 8).is_err() {
|
||
tty.write(core, &[8], 1)?;
|
||
}
|
||
if tty.put_char(tty.core(), b' ').is_err() {
|
||
tty.write(core, b" ", 1)?;
|
||
}
|
||
self.cursor_column -= 1;
|
||
space -= 1;
|
||
tail += 1;
|
||
}
|
||
_ => {
|
||
// 不是特殊字节码,则表示控制字符 例如 ^C
|
||
if space < 2 {
|
||
break;
|
||
}
|
||
|
||
if tty.put_char(tty.core(), b'^').is_err() {
|
||
tty.write(core, b"^", 1)?;
|
||
}
|
||
|
||
if tty.put_char(tty.core(), ch ^ 0o100).is_err() {
|
||
tty.write(core, &[ch ^ 0o100], 1)?;
|
||
}
|
||
|
||
self.cursor_column += 2;
|
||
space -= 2;
|
||
tail += 2;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
if termios.output_mode.contains(OutputMode::OPOST) {
|
||
let ret = self.do_output_char(tty.clone(), c, space);
|
||
|
||
if ret.is_err() {
|
||
break;
|
||
}
|
||
space -= ret.unwrap();
|
||
} else {
|
||
if space == 0 {
|
||
break;
|
||
}
|
||
|
||
if tty.put_char(tty.core(), c).is_err() {
|
||
tty.write(core, &[c], 1)?;
|
||
}
|
||
space -= 1;
|
||
}
|
||
tail += 1;
|
||
}
|
||
}
|
||
|
||
// 如果回显缓冲区接近满(在下一次提交之前可能会发生回显溢出的情况),则丢弃足够的尾部数据以防止随后的溢出。
|
||
while self.echo_commit > tail && self.echo_commit - tail >= ECHO_DISCARD_WATERMARK {
|
||
if self.echo_buf[ntty_buf_mask(tail)] == EchoOperation::Start.to_u8() {
|
||
if self.echo_buf[ntty_buf_mask(tail + 1)] == EchoOperation::EraseTab.to_u8() {
|
||
tail += 3;
|
||
} else {
|
||
tail += 2;
|
||
}
|
||
} else {
|
||
tail += 1;
|
||
}
|
||
}
|
||
|
||
self.echo_tail = tail;
|
||
return Ok(ospace - space);
|
||
}
|
||
|
||
/// ## 处理输出字符(带有 OPOST 处理)
|
||
pub fn process_output(&mut self, tty: Arc<TtyCore>, c: u8) -> bool {
|
||
let space = tty.write_room(tty.core());
|
||
|
||
if self.do_output_char(tty, c, space).is_err() {
|
||
return false;
|
||
}
|
||
|
||
true
|
||
}
|
||
|
||
// ## 设置带有 OPOST 处理的tty输出一个字符
|
||
pub fn do_output_char(
|
||
&mut self,
|
||
tty: Arc<TtyCore>,
|
||
c: u8,
|
||
space: usize,
|
||
) -> Result<usize, SystemError> {
|
||
if space == 0 {
|
||
return Err(SystemError::ENOBUFS);
|
||
}
|
||
|
||
let termios = tty.core().termios();
|
||
let core = tty.core();
|
||
let mut c = c;
|
||
if c as usize == 8 {
|
||
// 表示退格
|
||
if self.cursor_column > 0 {
|
||
self.cursor_column -= 1;
|
||
}
|
||
if tty.put_char(tty.core(), c).is_err() {
|
||
tty.write(core, &[c], 1)?;
|
||
}
|
||
return Ok(1);
|
||
}
|
||
match c as char {
|
||
'\n' => {
|
||
if termios.output_mode.contains(OutputMode::ONLRET) {
|
||
// 回车符
|
||
self.cursor_column = 0;
|
||
}
|
||
if termios.output_mode.contains(OutputMode::ONLCR) {
|
||
// 映射为“\r\n”
|
||
if space < 2 {
|
||
return Err(SystemError::ENOBUFS);
|
||
}
|
||
self.cursor_column = 0;
|
||
self.canon_cursor_column = 0;
|
||
|
||
// 通过驱动写入
|
||
tty.write(core, "\r\n".as_bytes(), 2)?;
|
||
return Ok(2);
|
||
}
|
||
|
||
self.canon_cursor_column = self.cursor_column;
|
||
}
|
||
'\r' => {
|
||
if termios.output_mode.contains(OutputMode::ONOCR) && self.cursor_column == 0 {
|
||
// 光标已经在第0列,则不输出回车符
|
||
return Ok(0);
|
||
}
|
||
|
||
if termios.output_mode.contains(OutputMode::OCRNL) {
|
||
// 输出的\r映射为\n
|
||
c = b'\n';
|
||
if termios.output_mode.contains(OutputMode::ONLRET) {
|
||
// \r映射为\n,但是保留\r特性
|
||
self.cursor_column = 0;
|
||
self.canon_cursor_column = 0;
|
||
}
|
||
} else {
|
||
self.cursor_column = 0;
|
||
self.canon_cursor_column = 0;
|
||
}
|
||
}
|
||
'\t' => {
|
||
// 计算输出一个\t需要的空间
|
||
let spaces = 8 - (self.cursor_column & 7) as usize;
|
||
if termios.output_mode.contains(OutputMode::TABDLY)
|
||
&& OutputMode::TABDLY.bits() == OutputMode::XTABS.bits()
|
||
{
|
||
// 配置的tab选项是真正输出空格到驱动
|
||
if space < spaces {
|
||
// 空间不够
|
||
return Err(SystemError::ENOBUFS);
|
||
}
|
||
self.cursor_column += spaces as u32;
|
||
// 写入sapces个空格
|
||
tty.write(core, " ".as_bytes(), spaces)?;
|
||
return Ok(spaces);
|
||
}
|
||
self.cursor_column += spaces as u32;
|
||
}
|
||
_ => {
|
||
// 判断是否为控制字符
|
||
if !(c as char).is_control() {
|
||
if termios.output_mode.contains(OutputMode::OLCUC) {
|
||
c = c.to_ascii_uppercase();
|
||
}
|
||
|
||
// 判断是否为utf8模式下的连续字符
|
||
if !(termios.input_mode.contains(InputMode::IUTF8)
|
||
&& (c as usize) & 0xc0 == 0x80)
|
||
{
|
||
self.cursor_column += 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if tty.put_char(tty.core(), c).is_err() {
|
||
tty.write(core, &[c], 1)?;
|
||
}
|
||
Ok(1)
|
||
}
|
||
|
||
fn packet_mode_flush(&self, tty: &TtyCoreData) {
|
||
let link = tty.link().unwrap();
|
||
if link.core().contorl_info_irqsave().packet {
|
||
tty.contorl_info_irqsave()
|
||
.pktstatus
|
||
.insert(TtyPacketStatus::TIOCPKT_FLUSHREAD);
|
||
|
||
link.core().read_wq().wakeup_all();
|
||
}
|
||
}
|
||
}
|
||
|
||
impl TtyLineDiscipline for NTtyLinediscipline {
|
||
fn open(&self, tty: Arc<TtyCore>) -> Result<(), system_error::SystemError> {
|
||
// 反向绑定tty到disc
|
||
self.disc_data().tty = Arc::downgrade(&tty);
|
||
// 特定的tty设备在这里可能需要取消端口节流
|
||
return self.set_termios(tty, None);
|
||
}
|
||
|
||
fn close(&self, _tty: Arc<TtyCore>) -> Result<(), system_error::SystemError> {
|
||
todo!()
|
||
}
|
||
|
||
/// ## 重置缓冲区的基本信息
|
||
fn flush_buffer(&self, tty: Arc<TtyCore>) -> Result<(), system_error::SystemError> {
|
||
let core = tty.core();
|
||
let _ = core.termios();
|
||
let mut ldata = self.disc_data();
|
||
ldata.read_head = 0;
|
||
ldata.canon_head = 0;
|
||
ldata.read_tail = 0;
|
||
ldata.commit_head = 0;
|
||
ldata.line_start = 0;
|
||
ldata.erasing = false;
|
||
ldata.read_flags.set_all(false);
|
||
ldata.pushing = false;
|
||
ldata.lookahead_count = 0;
|
||
|
||
// todo: kick worker?
|
||
// packet mode?
|
||
if core.link().is_some() {
|
||
ldata.packet_mode_flush(core);
|
||
}
|
||
|
||
Ok(())
|
||
}
|
||
|
||
#[inline(never)]
|
||
fn read(
|
||
&self,
|
||
tty: Arc<TtyCore>,
|
||
buf: &mut [u8],
|
||
len: usize,
|
||
cookie: &mut bool,
|
||
_offset: usize,
|
||
mode: FileMode,
|
||
) -> Result<usize, system_error::SystemError> {
|
||
let mut ldata;
|
||
if mode.contains(FileMode::O_NONBLOCK) {
|
||
let ret = self.disc_data_try_lock();
|
||
if ret.is_err() {
|
||
return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
|
||
}
|
||
ldata = ret.unwrap();
|
||
} else {
|
||
ldata = self.disc_data();
|
||
}
|
||
let core = tty.core();
|
||
let termios = core.termios();
|
||
let mut nr = len;
|
||
|
||
let mut offset = 0;
|
||
|
||
// 表示接着读
|
||
if *cookie {
|
||
// 规范且非拓展模式
|
||
if ldata.icanon && !termios.local_mode.contains(LocalMode::EXTPROC) {
|
||
// 跳过EOF字符
|
||
if len == 0 {
|
||
ldata.canon_skip_eof();
|
||
} else if ldata.canon_copy_from_read_buf(buf, &mut nr, &mut offset)? {
|
||
return Ok(len - nr);
|
||
}
|
||
} else if ldata.copy_from_read_buf(termios, buf, &mut nr, &mut offset)? {
|
||
return Ok(len - nr);
|
||
}
|
||
|
||
// 没有数据可读
|
||
|
||
// todo: kick worker? or 关闭节流?
|
||
|
||
*cookie = false;
|
||
return Ok(len - nr);
|
||
}
|
||
|
||
drop(termios);
|
||
|
||
TtyJobCtrlManager::tty_check_change(tty.clone(), Signal::SIGTTIN)?;
|
||
|
||
let mut minimum: usize = 0;
|
||
if !ldata.icanon {
|
||
let core = tty.core();
|
||
let termios = core.termios();
|
||
minimum = termios.control_characters[ControlCharIndex::VMIN] as usize;
|
||
if minimum == 0 {
|
||
minimum = 1;
|
||
}
|
||
}
|
||
|
||
let packet = core.contorl_info_irqsave().packet;
|
||
let mut ret: Result<usize, SystemError> = Ok(0);
|
||
// 记录读取前 的tail
|
||
let tail = ldata.read_tail;
|
||
drop(ldata);
|
||
while nr != 0 {
|
||
// todo: 处理packet模式
|
||
if packet {
|
||
let link = core.link().unwrap();
|
||
let link = link.core();
|
||
let mut ctrl = link.contorl_info_irqsave();
|
||
if !ctrl.pktstatus.is_empty() {
|
||
if offset != 0 {
|
||
break;
|
||
}
|
||
let cs = ctrl.pktstatus;
|
||
ctrl.pktstatus = TtyPacketStatus::empty();
|
||
|
||
buf[offset] = cs.bits();
|
||
offset += 1;
|
||
// nr -= 1;
|
||
break;
|
||
}
|
||
}
|
||
|
||
let mut ldata = self.disc_data();
|
||
|
||
let core = tty.core();
|
||
if !ldata.input_available(core.termios(), false) {
|
||
if core.flags().contains(TtyFlag::OTHER_CLOSED) {
|
||
ret = Err(SystemError::EIO);
|
||
break;
|
||
}
|
||
|
||
if core.flags().contains(TtyFlag::HUPPED) || core.flags().contains(TtyFlag::HUPPING)
|
||
{
|
||
break;
|
||
}
|
||
|
||
if mode.contains(FileMode::O_NONBLOCK)
|
||
|| core.flags().contains(TtyFlag::LDISC_CHANGING)
|
||
{
|
||
ret = Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
|
||
break;
|
||
}
|
||
|
||
if ProcessManager::current_pcb().has_pending_signal_fast() {
|
||
ProcessManager::current_pcb()
|
||
.flags()
|
||
.insert(ProcessFlags::HAS_PENDING_SIGNAL);
|
||
|
||
ret = Err(SystemError::ERESTARTSYS);
|
||
break;
|
||
}
|
||
|
||
// 休眠一段时间
|
||
// 获取到termios读锁,避免termios被更改导致行为异常
|
||
// let termios = core.termios_preempt_enable();
|
||
// let helper = WakeUpHelper::new(ProcessManager::current_pcb());
|
||
// let wakeup_helper = Timer::new(helper, timeout);
|
||
// wakeup_helper.activate();
|
||
// drop(termios);
|
||
drop(ldata);
|
||
core.read_wq()
|
||
.sleep((EPollEventType::EPOLLIN | EPollEventType::EPOLLRDNORM).bits() as u64);
|
||
continue;
|
||
}
|
||
|
||
if ldata.icanon && !core.termios().local_mode.contains(LocalMode::EXTPROC) {
|
||
if ldata.canon_copy_from_read_buf(buf, &mut nr, &mut offset)? {
|
||
*cookie = true;
|
||
offset += len - nr;
|
||
return Ok(offset);
|
||
}
|
||
} else {
|
||
// 非标准模式
|
||
// todo: 处理packet模式
|
||
if packet && offset == 0 {
|
||
buf[offset] = TtyPacketStatus::TIOCPKT_DATA.bits();
|
||
offset += 1;
|
||
nr -= 1;
|
||
}
|
||
// 拷贝数据
|
||
if ldata.copy_from_read_buf(core.termios(), buf, &mut nr, &mut offset)?
|
||
&& offset >= minimum
|
||
{
|
||
*cookie = true;
|
||
return Ok(offset);
|
||
}
|
||
}
|
||
|
||
if offset >= minimum {
|
||
break;
|
||
}
|
||
}
|
||
let ldata = self.disc_data();
|
||
if tail != ldata.read_tail {
|
||
// todo: kick worker?
|
||
}
|
||
|
||
if offset > 0 {
|
||
return Ok(offset);
|
||
}
|
||
|
||
ret
|
||
}
|
||
|
||
#[inline(never)]
|
||
fn write(
|
||
&self,
|
||
tty: Arc<TtyCore>,
|
||
buf: &[u8],
|
||
len: usize,
|
||
mode: FileMode,
|
||
) -> Result<usize, system_error::SystemError> {
|
||
let mut nr = len;
|
||
let mut ldata = self.disc_data();
|
||
let pcb = ProcessManager::current_pcb();
|
||
let binding = tty.clone();
|
||
let core = binding.core();
|
||
let termios = *core.termios();
|
||
if termios.local_mode.contains(LocalMode::TOSTOP) {
|
||
TtyJobCtrlManager::tty_check_change(tty.clone(), Signal::SIGTTOU)?;
|
||
}
|
||
|
||
ldata.process_echoes(tty.clone());
|
||
// drop(ldata);
|
||
let mut offset = 0;
|
||
loop {
|
||
if pcb.has_pending_signal_fast() {
|
||
ProcessManager::current_pcb()
|
||
.flags()
|
||
.insert(ProcessFlags::HAS_PENDING_SIGNAL);
|
||
|
||
return Err(SystemError::ERESTARTSYS);
|
||
}
|
||
if core.flags().contains(TtyFlag::HUPPED) {
|
||
return Err(SystemError::EIO);
|
||
}
|
||
if termios.output_mode.contains(OutputMode::OPOST) {
|
||
while nr > 0 {
|
||
// let mut ldata = self.disc_data();
|
||
// 获得一次处理后的数量
|
||
let ret = ldata.process_output_block(core, core.termios(), &buf[offset..], nr);
|
||
let num = match ret {
|
||
Ok(num) => num,
|
||
Err(e) => {
|
||
if e == SystemError::EAGAIN_OR_EWOULDBLOCK {
|
||
break;
|
||
} else {
|
||
return Err(e);
|
||
}
|
||
}
|
||
};
|
||
|
||
offset += num;
|
||
nr -= num;
|
||
|
||
if nr == 0 {
|
||
break;
|
||
}
|
||
|
||
let c = buf[offset];
|
||
if !ldata.process_output(tty.clone(), c) {
|
||
break;
|
||
}
|
||
offset += 1;
|
||
nr -= 1;
|
||
}
|
||
|
||
tty.flush_chars(core);
|
||
} else {
|
||
while nr > 0 {
|
||
let write = tty.write(core, &buf[offset..], nr)?;
|
||
if write == 0 {
|
||
break;
|
||
}
|
||
offset += write;
|
||
nr -= write;
|
||
}
|
||
}
|
||
|
||
if nr == 0 {
|
||
break;
|
||
}
|
||
|
||
if mode.contains(FileMode::O_NONBLOCK) || core.flags().contains(TtyFlag::LDISC_CHANGING)
|
||
{
|
||
return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
|
||
}
|
||
|
||
// 到这里表明没位置可写了
|
||
// 休眠一段时间
|
||
// 获取到termios读锁,避免termios被更改导致行为异常
|
||
core.write_wq()
|
||
.sleep(EPollEventType::EPOLLOUT.bits() as u64);
|
||
}
|
||
|
||
Ok(offset)
|
||
}
|
||
|
||
fn ioctl(
|
||
&self,
|
||
tty: Arc<TtyCore>,
|
||
cmd: u32,
|
||
arg: usize,
|
||
) -> Result<usize, system_error::SystemError> {
|
||
match cmd {
|
||
TtyIoctlCmd::TIOCOUTQ => {
|
||
let mut user_writer = UserBufferWriter::new(
|
||
VirtAddr::new(arg).as_ptr::<i32>(),
|
||
core::mem::size_of::<i32>(),
|
||
true,
|
||
)?;
|
||
|
||
let count = tty.chars_in_buffer();
|
||
user_writer.copy_one_to_user::<i32>(&(count as i32), 0)?;
|
||
return Ok(0);
|
||
}
|
||
TtyIoctlCmd::FIONREAD => {
|
||
let ldata = self.disc_data();
|
||
let termios = tty.core().termios();
|
||
let retval;
|
||
if termios.local_mode.contains(LocalMode::ICANON)
|
||
&& !termios.local_mode.contains(LocalMode::EXTPROC)
|
||
{
|
||
if ldata.canon_head == ldata.read_tail {
|
||
retval = 0;
|
||
} else {
|
||
let head = ldata.canon_head;
|
||
let mut tail = ldata.read_tail;
|
||
let mut nr = head - tail;
|
||
|
||
while ntty_buf_mask(head) != ntty_buf_mask(tail) {
|
||
if ldata.read_flags.get(ntty_buf_mask(tail)).unwrap()
|
||
&& ldata.read_buf[ntty_buf_mask(tail)]
|
||
== ControlCharIndex::DISABLE_CHAR
|
||
{
|
||
nr -= 1;
|
||
}
|
||
tail += 1;
|
||
}
|
||
|
||
retval = nr;
|
||
}
|
||
} else {
|
||
retval = ldata.read_cnt();
|
||
}
|
||
|
||
let mut user_writer = UserBufferWriter::new(
|
||
VirtAddr::new(arg).as_ptr::<i32>(),
|
||
core::mem::size_of::<i32>(),
|
||
true,
|
||
)?;
|
||
|
||
user_writer.copy_one_to_user::<i32>(&(retval as i32), 0)?;
|
||
return Ok(0);
|
||
}
|
||
_ => {
|
||
return self.ioctl_helper(tty, cmd, arg);
|
||
}
|
||
}
|
||
}
|
||
|
||
#[inline(never)]
|
||
fn set_termios(
|
||
&self,
|
||
tty: Arc<TtyCore>,
|
||
old: Option<crate::driver::tty::termios::Termios>,
|
||
) -> Result<(), system_error::SystemError> {
|
||
let core = tty.core();
|
||
let termios = core.termios();
|
||
let mut ldata = self.disc_data();
|
||
let contorl_chars = termios.control_characters;
|
||
|
||
// 第一次设置或者规范模式 (ICANON) 或者扩展处理 (EXTPROC) 标志发生变化
|
||
let mut spec_mode_changed = false;
|
||
if let Some(old) = old {
|
||
let local_mode = old.local_mode.bitxor(termios.local_mode);
|
||
spec_mode_changed =
|
||
local_mode.contains(LocalMode::ICANON) || local_mode.contains(LocalMode::EXTPROC);
|
||
}
|
||
if old.is_none() || spec_mode_changed {
|
||
// 重置read_flags
|
||
ldata.read_flags.set_all(false);
|
||
|
||
ldata.line_start = ldata.read_tail;
|
||
|
||
// 不是规范模式或者有可读数据
|
||
if !termios.local_mode.contains(LocalMode::ICANON) || ldata.read_cnt() != 0 {
|
||
ldata.canon_head = ldata.read_tail;
|
||
ldata.pushing = false;
|
||
} else {
|
||
let read_head = ldata.read_head;
|
||
ldata
|
||
.read_flags
|
||
.set((read_head - 1) & (NTTY_BUFSIZE - 1), true);
|
||
ldata.canon_head = ldata.read_head;
|
||
ldata.pushing = true;
|
||
}
|
||
ldata.commit_head = ldata.read_head;
|
||
ldata.erasing = false;
|
||
ldata.lnext = false;
|
||
}
|
||
|
||
// 设置模式
|
||
ldata.icanon = termios.local_mode.contains(LocalMode::ICANON);
|
||
|
||
// 设置回显
|
||
if termios.local_mode.contains(LocalMode::ECHO) {
|
||
ldata.echo = true;
|
||
}
|
||
|
||
if termios.input_mode.contains(InputMode::ISTRIP)
|
||
|| termios.input_mode.contains(InputMode::IUCLC)
|
||
|| termios.input_mode.contains(InputMode::IGNCR)
|
||
|| termios.input_mode.contains(InputMode::IXON)
|
||
|| termios.local_mode.contains(LocalMode::ISIG)
|
||
|| termios.local_mode.contains(LocalMode::ECHO)
|
||
|| termios.input_mode.contains(InputMode::PARMRK)
|
||
{
|
||
// 非原模式
|
||
|
||
ldata.char_map.set_all(false);
|
||
|
||
// 忽略回车符或者将回车映射为换行符
|
||
if termios.input_mode.contains(InputMode::IGNCR)
|
||
|| termios.input_mode.contains(InputMode::ICRNL)
|
||
{
|
||
ldata.char_map.set('\r' as usize, true);
|
||
}
|
||
|
||
// 将换行映射为回车
|
||
if termios.input_mode.contains(InputMode::INLCR) {
|
||
ldata.char_map.set('\n' as usize, true);
|
||
}
|
||
|
||
// 规范模式
|
||
if termios.local_mode.contains(LocalMode::ICANON) {
|
||
ldata
|
||
.char_map
|
||
.set(contorl_chars[ControlCharIndex::VERASE] as usize, true);
|
||
ldata
|
||
.char_map
|
||
.set(contorl_chars[ControlCharIndex::VKILL] as usize, true);
|
||
ldata
|
||
.char_map
|
||
.set(contorl_chars[ControlCharIndex::VEOF] as usize, true);
|
||
ldata.char_map.set('\n' as usize, true);
|
||
ldata
|
||
.char_map
|
||
.set(contorl_chars[ControlCharIndex::VEOL] as usize, true);
|
||
|
||
if termios.local_mode.contains(LocalMode::IEXTEN) {
|
||
ldata
|
||
.char_map
|
||
.set(contorl_chars[ControlCharIndex::VWERASE] as usize, true);
|
||
ldata
|
||
.char_map
|
||
.set(contorl_chars[ControlCharIndex::VLNEXT] as usize, true);
|
||
ldata
|
||
.char_map
|
||
.set(contorl_chars[ControlCharIndex::VEOL2] as usize, true);
|
||
if termios.local_mode.contains(LocalMode::ECHO) {
|
||
ldata
|
||
.char_map
|
||
.set(contorl_chars[ControlCharIndex::VREPRINT] as usize, true);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 软件流控制
|
||
if termios.input_mode.contains(InputMode::IXON) {
|
||
ldata
|
||
.char_map
|
||
.set(contorl_chars[ControlCharIndex::VSTART] as usize, true);
|
||
ldata
|
||
.char_map
|
||
.set(contorl_chars[ControlCharIndex::VSTOP] as usize, true);
|
||
}
|
||
|
||
if termios.local_mode.contains(LocalMode::ISIG) {
|
||
ldata
|
||
.char_map
|
||
.set(contorl_chars[ControlCharIndex::VINTR] as usize, true);
|
||
ldata
|
||
.char_map
|
||
.set(contorl_chars[ControlCharIndex::VQUIT] as usize, true);
|
||
ldata
|
||
.char_map
|
||
.set(contorl_chars[ControlCharIndex::VSUSP] as usize, true);
|
||
}
|
||
|
||
ldata
|
||
.char_map
|
||
.set(ControlCharIndex::DISABLE_CHAR as usize, true);
|
||
ldata.raw = false;
|
||
ldata.real_raw = false;
|
||
} else {
|
||
// 原模式或real_raw
|
||
ldata.raw = true;
|
||
|
||
ldata.real_raw = termios.input_mode.contains(InputMode::IGNBRK)
|
||
|| (!termios.input_mode.contains(InputMode::BRKINT)
|
||
&& !termios.input_mode.contains(InputMode::PARMRK))
|
||
&& (termios.input_mode.contains(InputMode::IGNPAR)
|
||
|| !termios.input_mode.contains(InputMode::INPCK))
|
||
&& (core
|
||
.driver()
|
||
.flags()
|
||
.contains(TtyDriverFlag::TTY_DRIVER_REAL_RAW));
|
||
}
|
||
|
||
// if !termios.input_mode.contains(InputMode::IXON)
|
||
// && old.is_some()
|
||
// && old.unwrap().input_mode.contains(InputMode::IXON) && !
|
||
// {}
|
||
|
||
core.read_wq().wakeup_all();
|
||
core.write_wq().wakeup_all();
|
||
Ok(())
|
||
}
|
||
|
||
fn poll(&self, tty: Arc<TtyCore>) -> Result<usize, system_error::SystemError> {
|
||
let core = tty.core();
|
||
let ldata = self.disc_data();
|
||
|
||
let mut event = EPollEventType::empty();
|
||
if ldata.input_available(core.termios(), true) {
|
||
event.insert(EPollEventType::EPOLLIN | EPollEventType::EPOLLRDNORM)
|
||
}
|
||
|
||
if core.contorl_info_irqsave().packet {
|
||
let link = core.link();
|
||
if link.is_some()
|
||
&& !link
|
||
.unwrap()
|
||
.core()
|
||
.contorl_info_irqsave()
|
||
.pktstatus
|
||
.is_empty()
|
||
{
|
||
event.insert(
|
||
EPollEventType::EPOLLPRI
|
||
| EPollEventType::EPOLLIN
|
||
| EPollEventType::EPOLLRDNORM,
|
||
);
|
||
}
|
||
}
|
||
|
||
if core.flags().contains(TtyFlag::OTHER_CLOSED) {
|
||
event.insert(EPollEventType::EPOLLHUP);
|
||
}
|
||
|
||
if core.driver().driver_funcs().chars_in_buffer() < 256
|
||
&& core.driver().driver_funcs().write_room(core) > 0
|
||
{
|
||
event.insert(EPollEventType::EPOLLOUT | EPollEventType::EPOLLWRNORM);
|
||
}
|
||
|
||
Ok(event.bits() as usize)
|
||
}
|
||
|
||
fn hangup(&self, _tty: Arc<TtyCore>) -> Result<(), system_error::SystemError> {
|
||
todo!()
|
||
}
|
||
|
||
fn receive_buf(
|
||
&self,
|
||
tty: Arc<TtyCore>,
|
||
buf: &[u8],
|
||
flags: Option<&[u8]>,
|
||
count: usize,
|
||
) -> Result<usize, SystemError> {
|
||
let mut ldata = self.disc_data();
|
||
ldata.receive_buf_common(tty, buf, flags, count, false)
|
||
}
|
||
|
||
fn receive_buf2(
|
||
&self,
|
||
tty: Arc<TtyCore>,
|
||
buf: &[u8],
|
||
flags: Option<&[u8]>,
|
||
count: usize,
|
||
) -> Result<usize, SystemError> {
|
||
let mut ldata = self.disc_data();
|
||
ldata.receive_buf_common(tty, buf, flags, count, true)
|
||
}
|
||
}
|