kthread.rs 2.2 KB

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