Browse Source

fix: 键盘中断上下文不再直接操作tty,而是由专门的kthread来渲染 (#592)

fix: 键盘中断上下文不再直接操作tty,而是由专门的kthread来渲染
1.修正psmouse 日志
2. 键盘中断上下文不再直接操作tty,而是由专门的kthread来渲染
3. 由于调度器设计问题,load balance会由于时序问题导致错误.因此暂时只启用单核.
LoGin 1 year ago
parent
commit
59fdb447ee

+ 2 - 1
kernel/src/driver/input/ps2_mouse/ps_mouse_driver.rs

@@ -276,9 +276,10 @@ impl SerioDriver for Ps2MouseDriver {
 
 #[unified_init(INITCALL_DEVICE)]
 fn ps2_mouse_driver_init() -> Result<(), SystemError> {
-    kdebug!("Ps2_mouse_drive initing...");
+    kdebug!("Ps2_mouse_drive initializing...");
     let driver = Ps2MouseDriver::new();
     serio_driver_manager().register(driver.clone())?;
     unsafe { PS2_MOUSE_DRIVER = Some(driver) };
+    kdebug!("Ps2_mouse_drive initialized!");
     return Ok(());
 }

+ 66 - 0
kernel/src/driver/tty/kthread.rs

@@ -0,0 +1,66 @@
+//! tty刷新内核线程
+
+use alloc::{string::ToString, sync::Arc};
+use kdepends::thingbuf::StaticThingBuf;
+
+use crate::{
+    arch::sched::sched,
+    process::{
+        kthread::{KernelThreadClosure, KernelThreadMechanism},
+        ProcessControlBlock, ProcessFlags,
+    },
+};
+
+use super::tty_port::current_tty_port;
+
+/// 用于缓存键盘输入的缓冲区
+static KEYBUF: StaticThingBuf<u8, 512> = StaticThingBuf::new();
+
+static mut TTY_REFRESH_THREAD: Option<Arc<ProcessControlBlock>> = None;
+
+pub(super) fn tty_flush_thread_init() {
+    let closure =
+        KernelThreadClosure::StaticEmptyClosure((&(tty_refresh_thread as fn() -> i32), ()));
+    let pcb = KernelThreadMechanism::create_and_run(closure, "tty_refresh".to_string())
+        .ok_or("")
+        .expect("create tty_refresh thread failed");
+    unsafe {
+        TTY_REFRESH_THREAD = Some(pcb);
+    }
+}
+
+fn tty_refresh_thread() -> i32 {
+    const TO_DEQUEUE_MAX: usize = 256;
+    loop {
+        if KEYBUF.is_empty() {
+            // 如果缓冲区为空,就休眠
+            unsafe {
+                TTY_REFRESH_THREAD
+                    .as_ref()
+                    .unwrap()
+                    .flags()
+                    .insert(ProcessFlags::NEED_SCHEDULE)
+            };
+
+            sched();
+        }
+
+        let to_dequeue = core::cmp::min(KEYBUF.len(), TO_DEQUEUE_MAX);
+        if to_dequeue == 0 {
+            continue;
+        }
+        let mut data = [0u8; TO_DEQUEUE_MAX];
+        for i in 0..to_dequeue {
+            data[i] = KEYBUF.pop().unwrap();
+        }
+
+        let _ = current_tty_port().receive_buf(&data[0..to_dequeue], &[], to_dequeue);
+    }
+}
+
+/// 发送数据到tty刷新线程
+pub fn send_to_tty_refresh_thread(data: &[u8]) {
+    for i in 0..data.len() {
+        KEYBUF.push(data[i]).ok();
+    }
+}

+ 1 - 0
kernel/src/driver/tty/mod.rs

@@ -1,6 +1,7 @@
 use alloc::vec::Vec;
 
 pub mod console;
+pub mod kthread;
 pub mod termios;
 pub mod tty_core;
 pub mod tty_device;

+ 11 - 8
kernel/src/driver/tty/tty_core.rs

@@ -1,4 +1,7 @@
-use core::{fmt::Debug, sync::atomic::AtomicBool};
+use core::{
+    fmt::Debug,
+    sync::atomic::{AtomicBool, AtomicUsize},
+};
 
 use alloc::{collections::LinkedList, string::String, sync::Arc, vec::Vec};
 use system_error::SystemError;
@@ -43,7 +46,7 @@ impl TtyCore {
             termios: RwLock::new(termios),
             name,
             flags: RwLock::new(TtyFlag::empty()),
-            count: RwLock::new(0),
+            count: AtomicUsize::new(0),
             window_size: RwLock::new(WindowSize::default()),
             read_wq: EventWaitQueue::new(),
             write_wq: EventWaitQueue::new(),
@@ -129,7 +132,7 @@ impl TtyCore {
     }
 
     pub fn tty_wakeup(&self) {
-        if self.core.flags.read().contains(TtyFlag::DO_WRITE_WAKEUP) {
+        if self.core.flags().contains(TtyFlag::DO_WRITE_WAKEUP) {
             let _ = self.ldisc().write_wakeup(self.core());
         }
 
@@ -289,7 +292,7 @@ pub struct TtyCoreData {
     flags: RwLock<TtyFlag>,
     /// 在初始化时即确定不会更改,所以这里不用加锁
     index: usize,
-    count: RwLock<usize>,
+    count: AtomicUsize,
     /// 窗口大小
     window_size: RwLock<WindowSize>,
     /// 读等待队列
@@ -338,7 +341,7 @@ impl TtyCoreData {
 
     #[inline]
     pub fn flags(&self) -> TtyFlag {
-        self.flags.read().clone()
+        self.flags.read_irqsave().clone()
     }
 
     #[inline]
@@ -353,14 +356,14 @@ impl TtyCoreData {
 
     #[inline]
     pub fn set_termios(&self, termios: Termios) {
-        let mut termios_guard = self.termios.write_irqsave();
+        let mut termios_guard = self.termios_write();
         *termios_guard = termios;
     }
 
     #[inline]
     pub fn add_count(&self) {
-        let mut guard = self.count.write();
-        *guard += 1;
+        self.count
+            .fetch_add(1, core::sync::atomic::Ordering::SeqCst);
     }
 
     #[inline]

+ 3 - 0
kernel/src/driver/tty/tty_device.rs

@@ -36,6 +36,7 @@ use crate::{
 };
 
 use super::{
+    kthread::tty_flush_thread_init,
     termios::WindowSize,
     tty_core::{TtyCore, TtyFlag, TtyIoctlCmd},
     tty_driver::{TtyDriver, TtyDriverSubType, TtyDriverType, TtyOperation},
@@ -528,5 +529,7 @@ pub fn tty_init() -> Result<(), SystemError> {
     devfs_register(console.name, console)?;
 
     serial_init()?;
+
+    tty_flush_thread_init();
     return vty_init();
 }

+ 8 - 2
kernel/src/driver/tty/tty_port.rs

@@ -1,4 +1,4 @@
-use core::fmt::Debug;
+use core::{fmt::Debug, sync::atomic::Ordering};
 
 use alloc::{
     sync::{Arc, Weak},
@@ -12,7 +12,7 @@ use crate::{
     libs::spinlock::{SpinLock, SpinLockGuard},
 };
 
-use super::tty_core::TtyCore;
+use super::{tty_core::TtyCore, virtual_terminal::virtual_console::CURRENT_VCNUM};
 
 const TTY_PORT_BUFSIZE: usize = 4096;
 
@@ -27,6 +27,12 @@ lazy_static! {
     };
 }
 
+/// 获取当前tty port
+#[inline]
+pub fn current_tty_port() -> Arc<dyn TtyPort> {
+    TTY_PORTS[CURRENT_VCNUM.load(Ordering::SeqCst) as usize].clone()
+}
+
 #[allow(dead_code)]
 #[derive(Debug)]
 pub struct TtyPortData {

+ 1 - 2
kernel/src/init/initial_kthread.rs

@@ -27,9 +27,8 @@ pub fn initial_kernel_thread() -> i32 {
 }
 
 fn kernel_init() -> Result<(), SystemError> {
-    kenrel_init_freeable()?;
-
     KernelThreadMechanism::init_stage2();
+    kenrel_init_freeable()?;
 
     // 由于目前加锁,速度过慢,所以先不开启双缓冲
     // scm_enable_double_buffer().expect("Failed to enable double buffer");

+ 2 - 14
kernel/src/libs/keyboard_parser.rs

@@ -1,11 +1,4 @@
-use core::sync::atomic::Ordering;
-
-use alloc::sync::Arc;
-
-use crate::driver::tty::{
-    tty_port::{TtyPort, TTY_PORTS},
-    virtual_terminal::virtual_console::CURRENT_VCNUM,
-};
+use crate::driver::tty::kthread::send_to_tty_refresh_thread;
 
 #[allow(dead_code)]
 pub const NUM_SCAN_CODES: u8 = 0x80;
@@ -360,12 +353,7 @@ impl TypeOneFSMState {
     #[inline(always)]
     fn emit(ch: u8) {
         // 发送到tty
-        let _ = Self::current_port().receive_buf(&[ch], &[], 1);
-    }
-
-    #[inline]
-    fn current_port() -> Arc<dyn TtyPort> {
-        TTY_PORTS[CURRENT_VCNUM.load(Ordering::SeqCst) as usize].clone()
+        send_to_tty_refresh_thread(&[ch]);
     }
 
     /// @brief 处理Prtsc按下事件

+ 9 - 2
kernel/src/process/fork.rs

@@ -165,8 +165,15 @@ impl ProcessManager {
         let mut args = KernelCloneArgs::new();
         args.flags = clone_flags;
         args.exit_signal = Signal::SIGCHLD;
-
-        Self::copy_process(&current_pcb, &pcb, args, current_trapframe)?;
+        Self::copy_process(&current_pcb, &pcb, args, current_trapframe).map_err(|e| {
+            kerror!(
+                "fork: Failed to copy process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}",
+                current_pcb.pid(),
+                pcb.pid(),
+                e
+            );
+            e
+        })?;
         ProcessManager::add_pcb(pcb.clone());
 
         // 向procfs注册进程

+ 8 - 6
kernel/src/process/kthread.rs

@@ -87,9 +87,9 @@ impl KernelThreadPcbPrivate {
 #[allow(dead_code)]
 pub enum KernelThreadClosure {
     UsizeClosure((Box<dyn Fn(usize) -> i32 + Send + Sync>, usize)),
-    StaticUsizeClosure((&'static dyn Fn(usize) -> i32, usize)),
+    StaticUsizeClosure((&'static fn(usize) -> i32, usize)),
     EmptyClosure((Box<dyn Fn() -> i32 + Send + Sync>, ())),
-    StaticEmptyClosure((&'static dyn Fn() -> i32, ())),
+    StaticEmptyClosure((&'static fn() -> i32, ())),
     IrqThread(
         (
             &'static dyn Fn(Arc<IrqAction>) -> Result<(), SystemError>,
@@ -311,7 +311,7 @@ impl KernelThreadMechanism {
             unsafe {
                 KTHREAD_DAEMON_PCB.replace(pcb);
             }
-            kinfo!("Initializing kernel thread mechanism stage2 complete");
+            kinfo!("Initialize kernel thread mechanism stage2 complete");
         });
     }
 
@@ -435,6 +435,7 @@ impl KernelThreadMechanism {
     }
 
     /// A daemon thread which creates other kernel threads
+    #[inline(never)]
     fn kthread_daemon() -> i32 {
         let current_pcb = ProcessManager::current_pcb();
         kdebug!("kthread_daemon: pid: {:?}", current_pcb.pid());
@@ -454,9 +455,10 @@ impl KernelThreadMechanism {
                 drop(list);
 
                 // create a new kernel thread
-                let result: Result<Pid, SystemError> =
-                    Self::__inner_create(&info, CloneFlags::CLONE_FS | CloneFlags::CLONE_SIGNAL);
-
+                let result: Result<Pid, SystemError> = Self::__inner_create(
+                    &info,
+                    CloneFlags::CLONE_VM | CloneFlags::CLONE_FS | CloneFlags::CLONE_SIGNAL,
+                );
                 if result.is_err() {
                     // 创建失败
                     info.created

+ 1 - 1
kernel/src/process/mod.rs

@@ -439,6 +439,7 @@ impl ProcessManager {
 
 /// 上下文切换的钩子函数,当这个函数return的时候,将会发生上下文切换
 #[cfg(target_arch = "x86_64")]
+#[inline(never)]
 pub unsafe extern "sysv64" fn switch_finish_hook() {
     ProcessManager::switch_finish_hook();
 }
@@ -891,7 +892,6 @@ impl ProcessControlBlock {
 impl Drop for ProcessControlBlock {
     fn drop(&mut self) {
         let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
-        // kdebug!("drop: {:?}", self.pid);
         // 在ProcFS中,解除进程的注册
         procfs_unregister_pid(self.pid())
             .unwrap_or_else(|e| panic!("procfs_unregister_pid failed: error: {e:?}"));

+ 2 - 2
kernel/src/sched/core.rs

@@ -63,8 +63,8 @@ pub fn get_cpu_loads(cpu_id: ProcessorId) -> u32 {
 }
 // 负载均衡
 pub fn loads_balance(pcb: Arc<ProcessControlBlock>) {
-    // 对pcb的迁移情况进行调整
-
+    // FIXME: 由于目前负载均衡是直接添加到目标CPU的队列中,导致会由于时序问题导致进程在两个CPU上都存在。
+    // 在调度子系统重写/改进之前,暂时只设置进程在0号CPU上运行
     // 由于调度器问题,暂时不进行负载均衡,见issue: https://github.com/DragonOS-Community/DragonOS/issues/571
     let min_loads_cpu_id = ProcessorId::new(0);