Browse Source

feat(tty): 将tty设备适配epoll,修改串口部分问题 (#968)

- tty文件适配epoll,使epoll能够监听tty
- 修改串口handle_irq,原有每次只读取一个字节会导致:输入left(esc+[+A)被错误解析为(esc)+([)+(A)三个字符
- 为串口加上vcdata用于控制输入输出的格式问题(未解决,这个pr捎带)
GnoCiYeH 5 months ago
parent
commit
c709f79fda

+ 29 - 5
kernel/src/driver/serial/serial8250/serial8250_pio.rs

@@ -19,12 +19,14 @@ use crate::{
         },
         serial::{AtomicBaudRate, BaudRate, DivisorFraction, UartPort},
         tty::{
+            console::ConsoleSwitch,
             kthread::send_to_tty_refresh_thread,
             termios::WindowSize,
             tty_core::{TtyCore, TtyCoreData},
             tty_driver::{TtyDriver, TtyDriverManager, TtyOperation},
-            virtual_terminal::{vc_manager, VirtConsole},
+            virtual_terminal::{vc_manager, virtual_console::VirtualConsoleData, VirtConsole},
         },
+        video::console::dummycon::dummy_console,
     },
     exception::{
         irqdata::IrqHandlerData,
@@ -32,7 +34,7 @@ use crate::{
         manage::irq_manager,
         IrqNumber,
     },
-    libs::rwlock::RwLock,
+    libs::{rwlock::RwLock, spinlock::SpinLock},
 };
 use system_error::SystemError;
 
@@ -265,9 +267,20 @@ impl UartPort for Serial8250PIOPort {
     }
 
     fn handle_irq(&self) -> Result<(), SystemError> {
-        if let Some(c) = self.read_one_byte() {
-            send_to_tty_refresh_thread(&[c]);
+        let mut buf = [0; 8];
+        let mut index = 0;
+
+        // Read up to the size of the buffer
+        while index < buf.len() {
+            if let Some(c) = self.read_one_byte() {
+                buf[index] = c;
+                index += 1;
+            } else {
+                break; // No more bytes to read
+            }
         }
+
+        send_to_tty_refresh_thread(&buf[0..index]);
         Ok(())
     }
 
@@ -385,7 +398,18 @@ impl TtyOperation for Serial8250PIOTtyDriverInner {
         if tty.core().index() >= unsafe { PIO_PORTS.len() } {
             return Err(SystemError::ENODEV);
         }
-        let vc = VirtConsole::new(None);
+
+        *tty.core().window_size_write() = WindowSize::DEFAULT;
+        let vc_data = Arc::new(SpinLock::new(VirtualConsoleData::new(usize::MAX)));
+        let mut vc_data_guard = vc_data.lock_irqsave();
+        vc_data_guard.set_driver_funcs(Arc::downgrade(&dummy_console()) as Weak<dyn ConsoleSwitch>);
+        vc_data_guard.init(
+            Some(tty.core().window_size().row.into()),
+            Some(tty.core().window_size().col.into()),
+            true,
+        );
+        drop(vc_data_guard);
+        let vc = VirtConsole::new(Some(vc_data));
         let vc_index = vc_manager().alloc(vc.clone()).ok_or(SystemError::EBUSY)?;
         self.do_install(driver, tty, vc.clone()).inspect_err(|_| {
             vc_manager().free(vc_index);

+ 1 - 7
kernel/src/driver/tty/termios.rs

@@ -2,7 +2,7 @@ use super::tty_ldisc::LineDisciplineType;
 
 /// ## 窗口大小
 #[repr(C)]
-#[derive(Debug, Clone, Copy, PartialEq)]
+#[derive(Debug, Clone, Copy, PartialEq, Default)]
 pub struct WindowSize {
     /// 行
     pub row: u16,
@@ -26,12 +26,6 @@ impl WindowSize {
     }
 }
 
-impl Default for WindowSize {
-    fn default() -> Self {
-        Self::DEFAULT
-    }
-}
-
 #[derive(Debug, Clone, Copy)]
 pub struct Termios {
     pub input_mode: InputMode,

+ 56 - 1
kernel/src/driver/tty/tty_core.rs

@@ -31,7 +31,7 @@ use super::{
         TtyLineDiscipline,
     },
     tty_port::TtyPort,
-    virtual_terminal::{vc_manager, virtual_console::VirtualConsoleData},
+    virtual_terminal::{vc_manager, virtual_console::VirtualConsoleData, DrawRegion},
 };
 
 #[derive(Debug)]
@@ -489,6 +489,61 @@ impl TtyCoreData {
     pub fn add_epitem(&self, epitem: Arc<EPollItem>) {
         self.epitems.lock().push_back(epitem)
     }
+
+    pub fn eptiems(&self) -> &SpinLock<LinkedList<Arc<EPollItem>>> {
+        &self.epitems
+    }
+
+    pub fn do_write(&self, buf: &[u8], mut nr: usize) -> Result<usize, SystemError> {
+        // 关闭中断
+        if let Some(vc_data) = self.vc_data() {
+            let mut vc_data_guard = vc_data.lock_irqsave();
+            let mut offset = 0;
+
+            // 这个参数是用来扫描unicode字符的,但是这部分目前未完成,先写着
+            let mut rescan = false;
+            let mut ch: u32 = 0;
+
+            let mut draw = DrawRegion::default();
+
+            // 首先隐藏光标再写
+            vc_data_guard.hide_cursor();
+
+            while nr != 0 {
+                if !rescan {
+                    ch = buf[offset] as u32;
+                    offset += 1;
+                    nr -= 1;
+                }
+
+                let (tc, rescan_last) = vc_data_guard.translate(&mut ch);
+                if tc.is_none() {
+                    // 表示未转换完成
+                    continue;
+                }
+
+                let tc = tc.unwrap();
+                rescan = rescan_last;
+
+                if vc_data_guard.is_control(tc, ch) {
+                    vc_data_guard.flush(&mut draw);
+                    vc_data_guard.do_control(ch);
+                    continue;
+                }
+
+                if !vc_data_guard.console_write_normal(tc, ch, &mut draw) {
+                    continue;
+                }
+            }
+
+            vc_data_guard.flush(&mut draw);
+
+            // TODO: notify update
+            return Ok(offset);
+        } else {
+            return Ok(0);
+        }
+    }
 }
 
 impl TtyOperation for TtyCore {

+ 6 - 1
kernel/src/driver/tty/tty_port.rs

@@ -4,7 +4,10 @@ use alloc::sync::{Arc, Weak};
 use kdepends::thingbuf::mpsc;
 use system_error::SystemError;
 
-use crate::libs::spinlock::{SpinLock, SpinLockGuard};
+use crate::{
+    libs::spinlock::{SpinLock, SpinLockGuard},
+    net::event_poll::EventPoll,
+};
 
 use super::tty_core::TtyCore;
 
@@ -85,6 +88,8 @@ pub trait TtyPort: Sync + Send + Debug {
             return ld.receive_buf(tty, buf, None, count);
         }
 
+        EventPoll::wakeup_epoll(tty.core().eptiems(), None)?;
+
         ret
     }
 }

+ 1 - 50
kernel/src/driver/tty/virtual_terminal/mod.rs

@@ -300,55 +300,6 @@ impl TtyConsoleDriverInner {
         Ok(Self { console })
     }
 
-    fn do_write(&self, tty: &TtyCoreData, buf: &[u8], mut nr: usize) -> Result<usize, SystemError> {
-        // 关闭中断
-        let vc_data = tty.vc_data().unwrap();
-        let mut vc_data_guard = vc_data.lock_irqsave();
-
-        let mut offset = 0;
-
-        // 这个参数是用来扫描unicode字符的,但是这部分目前未完成,先写着
-        let mut rescan = false;
-        let mut ch: u32 = 0;
-
-        let mut draw = DrawRegion::default();
-
-        // 首先隐藏光标再写
-        vc_data_guard.hide_cursor();
-
-        while nr != 0 {
-            if !rescan {
-                ch = buf[offset] as u32;
-                offset += 1;
-                nr -= 1;
-            }
-
-            let (tc, rescan_last) = vc_data_guard.translate(&mut ch);
-            if tc.is_none() {
-                // 表示未转换完成
-                continue;
-            }
-
-            let tc = tc.unwrap();
-            rescan = rescan_last;
-
-            if vc_data_guard.is_control(tc, ch) {
-                vc_data_guard.flush(&mut draw);
-                vc_data_guard.do_control(ch);
-                continue;
-            }
-
-            if !vc_data_guard.console_write_normal(tc, ch, &mut draw) {
-                continue;
-            }
-        }
-
-        vc_data_guard.flush(&mut draw);
-
-        // TODO: notify update
-        return Ok(offset);
-    }
-
     fn do_install(&self, tty: Arc<TtyCore>, vc: &Arc<VirtConsole>) -> Result<(), SystemError> {
         let tty_core = tty.core();
 
@@ -426,7 +377,7 @@ impl TtyOperation for TtyConsoleDriverInner {
         //     loop {}
         // }
         send_to_default_serial8250_port(buf);
-        let ret = self.do_write(tty, buf, nr);
+        let ret = tty.do_write(buf, nr);
         self.flush_chars(tty);
         ret
     }

+ 7 - 12
kernel/src/driver/tty/virtual_terminal/virtual_console.rs

@@ -206,7 +206,7 @@ impl VirtualConsoleData {
         }
     }
 
-    pub(super) fn init(&mut self, rows: Option<usize>, cols: Option<usize>, clear: bool) {
+    pub fn init(&mut self, rows: Option<usize>, cols: Option<usize>, clear: bool) {
         if let Some(rows) = rows {
             self.rows = rows;
         }
@@ -242,7 +242,7 @@ impl VirtualConsoleData {
         self.driver_funcs.as_ref().unwrap().upgrade().unwrap()
     }
 
-    pub(super) fn set_driver_funcs(&mut self, func: Weak<dyn ConsoleSwitch>) {
+    pub fn set_driver_funcs(&mut self, func: Weak<dyn ConsoleSwitch>) {
         self.driver_funcs = Some(func);
     }
 
@@ -312,7 +312,7 @@ impl VirtualConsoleData {
     ///
     /// ### 返回值
     /// ### (转换后的字符:i32,是否需要更多的数据才能进行转换:bool)
-    pub(super) fn translate(&mut self, c: &mut u32) -> (Option<u32>, bool) {
+    pub fn translate(&mut self, c: &mut u32) -> (Option<u32>, bool) {
         if self.vc_state != VirtualConsoleState::ESnormal {
             // 在控制字符状态下不需要翻译
             return (Some(*c), false);
@@ -440,7 +440,7 @@ impl VirtualConsoleData {
     const CTRL_ALWAYS: u32 = 0x0800f501;
 
     /// ## 用于判断tc(终端字符)在当前VC下是不是需要显示的控制字符
-    pub(super) fn is_control(&self, tc: u32, c: u32) -> bool {
+    pub fn is_control(&self, tc: u32, c: u32) -> bool {
         // 当前vc状态机不在正常状态,即在接收特殊字符的状态,则是控制字符
         if self.vc_state != VirtualConsoleState::ESnormal {
             return true;
@@ -1257,7 +1257,7 @@ impl VirtualConsoleData {
 
     /// ## 处理终端控制字符
     #[inline(never)]
-    pub(super) fn do_control(&mut self, ch: u32) {
+    pub fn do_control(&mut self, ch: u32) {
         // 首先检查是否处于 ANSI 控制字符串状态
         if self.vc_state.is_ansi_control_string() && (8..=13).contains(&ch) {
             return;
@@ -1534,12 +1534,7 @@ impl VirtualConsoleData {
     }
 
     #[inline(never)]
-    pub(super) fn console_write_normal(
-        &mut self,
-        mut tc: u32,
-        c: u32,
-        draw: &mut DrawRegion,
-    ) -> bool {
+    pub fn console_write_normal(&mut self, mut tc: u32, c: u32, draw: &mut DrawRegion) -> bool {
         let mut attr = self.attr;
         let himask = self.hi_font_mask;
         let charmask = if himask == 0 { 0xff } else { 0x1ff };
@@ -1753,7 +1748,7 @@ impl VirtualConsoleData {
         return (self.attr & 0x88) | ((self.attr & 0x70) >> 4) | ((self.attr & 0x07) << 4);
     }
 
-    pub(super) fn flush(&self, draw: &mut DrawRegion) {
+    pub fn flush(&self, draw: &mut DrawRegion) {
         if draw.x.is_none() {
             return;
         }

+ 2 - 2
kernel/src/filesystem/eventfd.rs

@@ -137,7 +137,7 @@ impl IndexNode for EventFdInode {
 
         let pollflag = EPollEventType::from_bits_truncate(self.poll(&data)? as u32);
         // 唤醒epoll中等待的进程
-        EventPoll::wakeup_epoll(&self.epitems, pollflag)?;
+        EventPoll::wakeup_epoll(&self.epitems, Some(pollflag))?;
 
         return Ok(8);
     }
@@ -184,7 +184,7 @@ impl IndexNode for EventFdInode {
 
         let pollflag = EPollEventType::from_bits_truncate(self.poll(&data)? as u32);
         // 唤醒epoll中等待的进程
-        EventPoll::wakeup_epoll(&self.epitems, pollflag)?;
+        EventPoll::wakeup_epoll(&self.epitems, Some(pollflag))?;
         return Ok(8);
     }
 

+ 9 - 0
kernel/src/filesystem/vfs/mount.rs

@@ -399,6 +399,15 @@ impl IndexNode for MountFSInode {
         return self.inner_inode.ioctl(cmd, data, private_data);
     }
 
+    #[inline]
+    fn kernel_ioctl(
+        &self,
+        arg: Arc<dyn crate::net::event_poll::KernelIoctlData>,
+        data: &FilePrivateData,
+    ) -> Result<usize, SystemError> {
+        return self.inner_inode.kernel_ioctl(arg, data);
+    }
+
     #[inline]
     fn list(&self) -> Result<alloc::vec::Vec<alloc::string::String>, SystemError> {
         return self.inner_inode.list();

+ 2 - 2
kernel/src/ipc/pipe.rs

@@ -267,7 +267,7 @@ impl IndexNode for LockedPipeInode {
 
         let pollflag = EPollEventType::from_bits_truncate(inode.poll(&data)? as u32);
         // 唤醒epoll中等待的进程
-        EventPoll::wakeup_epoll(&inode.epitems, pollflag)?;
+        EventPoll::wakeup_epoll(&inode.epitems, Some(pollflag))?;
 
         //返回读取的字节数
         return Ok(num);
@@ -413,7 +413,7 @@ impl IndexNode for LockedPipeInode {
 
         let pollflag = EPollEventType::from_bits_truncate(inode.poll(&data)? as u32);
         // 唤醒epoll中等待的进程
-        EventPoll::wakeup_epoll(&inode.epitems, pollflag)?;
+        EventPoll::wakeup_epoll(&inode.epitems, Some(pollflag))?;
 
         // 返回写入的字节数
         return Ok(len);

+ 35 - 26
kernel/src/net/event_poll/mod.rs

@@ -716,41 +716,50 @@ impl EventPoll {
     /// ### epoll的回调,支持epoll的文件有事件到来时直接调用该方法即可
     pub fn wakeup_epoll(
         epitems: &SpinLock<LinkedList<Arc<EPollItem>>>,
-        pollflags: EPollEventType,
+        pollflags: Option<EPollEventType>,
     ) -> Result<(), SystemError> {
         let mut epitems_guard = epitems.try_lock_irqsave()?;
         // 一次只取一个,因为一次也只有一个进程能拿到对应文件的🔓
         if let Some(epitem) = epitems_guard.pop_front() {
-            let epoll = epitem.epoll().upgrade().unwrap();
-            let mut epoll_guard = epoll.try_lock()?;
-            let binding = epitem.clone();
-            let event_guard = binding.event().read();
-            let ep_events = EPollEventType::from_bits_truncate(event_guard.events());
-
-            // 检查事件合理性以及是否有感兴趣的事件
-            if !(ep_events
-                .difference(EPollEventType::EP_PRIVATE_BITS)
-                .is_empty()
-                || pollflags.difference(ep_events).is_empty())
-            {
-                // TODO: 未处理pm相关
+            let pollflags = pollflags.unwrap_or({
+                if let Some(file) = epitem.file.upgrade() {
+                    EPollEventType::from_bits_truncate(file.poll()? as u32)
+                } else {
+                    EPollEventType::empty()
+                }
+            });
 
-                // 首先将就绪的epitem加入等待队列
-                epoll_guard.ep_add_ready(epitem.clone());
+            if let Some(epoll) = epitem.epoll().upgrade() {
+                let mut epoll_guard = epoll.try_lock()?;
+                let binding = epitem.clone();
+                let event_guard = binding.event().read();
+                let ep_events = EPollEventType::from_bits_truncate(event_guard.events());
 
-                if epoll_guard.ep_has_waiter() {
-                    if ep_events.contains(EPollEventType::EPOLLEXCLUSIVE)
-                        && !pollflags.contains(EPollEventType::POLLFREE)
-                    {
-                        // 避免惊群
-                        epoll_guard.ep_wake_one();
-                    } else {
-                        epoll_guard.ep_wake_all();
+                // 检查事件合理性以及是否有感兴趣的事件
+                if !(ep_events
+                    .difference(EPollEventType::EP_PRIVATE_BITS)
+                    .is_empty()
+                    || pollflags.difference(ep_events).is_empty())
+                {
+                    // TODO: 未处理pm相关
+
+                    // 首先将就绪的epitem加入等待队列
+                    epoll_guard.ep_add_ready(epitem.clone());
+
+                    if epoll_guard.ep_has_waiter() {
+                        if ep_events.contains(EPollEventType::EPOLLEXCLUSIVE)
+                            && !pollflags.contains(EPollEventType::POLLFREE)
+                        {
+                            // 避免惊群
+                            epoll_guard.ep_wake_one();
+                        } else {
+                            epoll_guard.ep_wake_all();
+                        }
                     }
                 }
-            }
 
-            epitems_guard.push_back(epitem);
+                epitems_guard.push_back(epitem);
+            }
         }
         Ok(())
     }

+ 1 - 1
kernel/src/net/net_core.rs

@@ -233,7 +233,7 @@ fn send_event(sockets: &smoltcp::iface::SocketSet) -> Result<(), SystemError> {
         }
         EventPoll::wakeup_epoll(
             &posix_item.epitems,
-            EPollEventType::from_bits_truncate(events as u32),
+            Some(EPollEventType::from_bits_truncate(events as u32)),
         )?;
         drop(handle_guard);
         // crate::debug!(