LoGin 2b72148cae
feat(syscall): 实现syscall restart (#1075)
能够在系统调用返回ERESTARTSYS时,信号处理结束后,自动重启系统调用.

TODO: 实现wait等需要restart_block的系统调用的重启

Signed-off-by: longjin <longjin@DragonOS.org>
2024-12-13 00:56:20 +08:00

2126 lines
69 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::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)
}
/// ## 用于处理带有 OPOSTOutput 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)
}
}