xref: /DragonOS/kernel/src/driver/tty/kthread.rs (revision dfe53cf087ef4c7b6db63d992906b062dc63e93f)
1 //! tty刷新内核线程
2 
3 use alloc::{string::ToString, sync::Arc};
4 use kdepends::thingbuf::StaticThingBuf;
5 
6 use crate::{
7     arch::sched::sched,
8     driver::tty::virtual_terminal::virtual_console::CURRENT_VCNUM,
9     process::{
10         kthread::{KernelThreadClosure, KernelThreadMechanism},
11         ProcessControlBlock, ProcessFlags,
12     },
13 };
14 
15 use super::tty_port::current_tty_port;
16 
17 /// 用于缓存键盘输入的缓冲区
18 static KEYBUF: StaticThingBuf<u8, 512> = StaticThingBuf::new();
19 
20 static mut TTY_REFRESH_THREAD: Option<Arc<ProcessControlBlock>> = None;
21 
22 pub(super) fn tty_flush_thread_init() {
23     let closure =
24         KernelThreadClosure::StaticEmptyClosure((&(tty_refresh_thread as fn() -> i32), ()));
25     let pcb = KernelThreadMechanism::create_and_run(closure, "tty_refresh".to_string())
26         .ok_or("")
27         .expect("create tty_refresh thread failed");
28     unsafe {
29         TTY_REFRESH_THREAD = Some(pcb);
30     }
31 }
32 
33 fn tty_refresh_thread() -> i32 {
34     const TO_DEQUEUE_MAX: usize = 256;
35     loop {
36         if KEYBUF.is_empty() {
37             // 如果缓冲区为空,就休眠
38             unsafe {
39                 TTY_REFRESH_THREAD
40                     .as_ref()
41                     .unwrap()
42                     .flags()
43                     .insert(ProcessFlags::NEED_SCHEDULE)
44             };
45 
46             sched();
47         }
48 
49         let to_dequeue = core::cmp::min(KEYBUF.len(), TO_DEQUEUE_MAX);
50         if to_dequeue == 0 {
51             continue;
52         }
53         let mut data = [0u8; TO_DEQUEUE_MAX];
54         for item in data.iter_mut().take(to_dequeue) {
55             *item = KEYBUF.pop().unwrap();
56         }
57 
58         if CURRENT_VCNUM.load(core::sync::atomic::Ordering::SeqCst) != -1 {
59             let _ = current_tty_port().receive_buf(&data[0..to_dequeue], &[], to_dequeue);
60         } else {
61             // 这里由于stdio未初始化,所以无法找到port
62             // TODO: 考虑改用双端队列,能够将丢失的输入插回
63         }
64     }
65 }
66 
67 /// 发送数据到tty刷新线程
68 pub fn send_to_tty_refresh_thread(data: &[u8]) {
69     for item in data {
70         KEYBUF.push(*item).ok();
71     }
72 }
73