xref: /DragonOS/kernel/src/driver/tty/mod.rs (revision 7eda31b2f07c6ef41dc0d2bd13051f0fce5e5976)
1 use core::intrinsics::unlikely;
2 
3 use alloc::string::String;
4 
5 use thingbuf::mpsc::{
6     self,
7     errors::{TryRecvError, TrySendError},
8 };
9 
10 use crate::libs::rwlock::RwLock;
11 
12 pub mod init;
13 pub mod serial;
14 pub mod tty_device;
15 pub mod tty_driver;
16 
17 bitflags! {
18     pub struct TtyCoreState: u32{
19         /// 在读取stdin缓冲区时,由于队列为空,有读者被阻塞
20         const BLOCK_AT_STDIN_READ = (1 << 0);
21         /// 开启输入回显。
22         const ECHO_ON = (1 << 1);
23     }
24 
25     #[derive(Default)]
26     pub struct TtyFileFlag:u32{
27         /// 当前文件是stdin文件
28         const STDIN = (1 << 0);
29         /// 当前文件是stdout文件
30         const STDOUT = (1 << 1);
31         /// 当前文件是stderr文件
32         const STDERR = (1 << 2);
33     }
34 }
35 
36 /// @brief tty文件的私有信息
37 #[derive(Debug, Default, Clone)]
38 pub struct TtyFilePrivateData {
39     flags: TtyFileFlag,
40 }
41 
42 /// @brief tty设备的核心功能结构体。在此结构体的基础上,衍生出TTY/PTY/PTS
43 ///
44 /// 每个TTY Core有5个端口:
45 /// - stdin:连接到一个活动进程的stdin文件描述符
46 /// - stdout:连接到多个进程的stdout文件描述符
47 /// - stderr:连接到多个进程的stdout文件描述符
48 /// - 输入端口:向tty设备输入数据的接口。输入到该接口的数据,将被导向stdin接口。
49 ///     如果开启了回显,那么,数据也将同时被导向输出端
50 /// - 输出端口:tty设备对外输出数据的端口。从stdout、stderr输入的数据,将会被导向此端口。
51 ///             此端口可以连接到屏幕、文件、或者是另一个tty core的输入端口。如果开启了
52 ///             输入数据回显,那么,输入端口的数据,将会被同时导向此端口,以及stdin端口
53 #[derive(Debug)]
54 struct TtyCore {
55     /// stdin的mpsc队列输入输出端
56     stdin_rx: mpsc::Receiver<u8>,
57     stdin_tx: mpsc::Sender<u8>,
58     /// 输出的mpsc队列输入输出端
59     output_rx: mpsc::Receiver<u8>,
60     output_tx: mpsc::Sender<u8>,
61 
62     /// tty核心的状态
63     state: RwLock<TtyCoreState>,
64 }
65 
66 #[derive(Debug)]
67 #[allow(dead_code)]
68 pub enum TtyError {
69     /// 缓冲区满,返回成功传送的字节数
70     BufferFull(usize),
71     /// 缓冲区空,返回成功传送的字节数
72     BufferEmpty(usize),
73     /// 设备已经被关闭
74     Closed,
75     /// End of file(已经读取的字符数,包含eof)
76     EOF(usize),
77     Unknown(String),
78 }
79 
80 impl TtyCore {
81     // 各个缓冲区的大小
82     pub const STDIN_BUF_SIZE: usize = 4096;
83     pub const OUTPUT_BUF_SIZE: usize = 4096;
84 
85     /// @brief 创建一个TTY核心组件
86     pub fn new() -> TtyCore {
87         let (stdin_tx, stdin_rx) = mpsc::channel::<u8>(Self::STDIN_BUF_SIZE);
88         let (output_tx, output_rx) = mpsc::channel::<u8>(Self::OUTPUT_BUF_SIZE);
89         let state: RwLock<TtyCoreState> = RwLock::new(TtyCoreState { bits: 0 });
90 
91         return TtyCore {
92             stdin_rx,
93             stdin_tx,
94             output_rx,
95             output_tx,
96             state,
97         };
98     }
99 
100     /// @brief 向tty的输入端口输入数据
101     ///
102     /// @param buf 输入数据
103     ///
104     /// @param block 是否允许阻塞
105     ///
106     /// @return Ok(成功传送的字节数)
107     /// @return Err(TtyError) 内部错误信息
108     pub fn input(&self, buf: &[u8], block: bool) -> Result<usize, TtyError> {
109         // TODO: 在这里考虑增加对信号发送的处理
110         let val = self.write_stdin(buf, block)?;
111         // 如果开启了输入回显,那么就写一份到输出缓冲区
112         if self.echo_enabled() {
113             self.write_output(&buf[0..val], true)?;
114         }
115         return Ok(val);
116     }
117 
118     /// @brief 从tty的输出端口读出数据
119     ///
120     /// @param buf 输出缓冲区
121     ///
122     /// @return Ok(成功传送的字节数)
123     /// @return Err(TtyError) 内部错误信息
124     #[inline]
125     pub fn output(&self, buf: &mut [u8], block: bool) -> Result<usize, TtyError> {
126         return self.read_output(buf, block);
127     }
128 
129     /// @brief tty的stdout接口
130     ///
131     /// @param buf 输入缓冲区
132     ///
133     /// @return Ok(成功传送的字节数)
134     /// @return Err(TtyError) 内部错误信息
135     #[inline]
136     pub fn stdout(&self, buf: &[u8], block: bool) -> Result<usize, TtyError> {
137         return self.write_output(buf, block);
138     }
139 
140     /// @brief tty的stderr接口
141     ///
142     /// @param buf 输入缓冲区
143     ///
144     /// @return Ok(成功传送的字节数)
145     /// @return Err(TtyError) 内部错误信息
146     #[inline]
147     pub fn stderr(&self, buf: &[u8], block: bool) -> Result<usize, TtyError> {
148         return self.write_output(buf, block);
149     }
150 
151     /// @brief 读取TTY的stdin缓冲区
152     ///
153     /// @param buf 读取到的位置
154     /// @param block 是否阻塞读
155     ///
156     /// @return Ok(成功读取的字节数)
157     /// @return Err(TtyError) 内部错误信息
158     pub fn read_stdin(&self, buf: &mut [u8], block: bool) -> Result<usize, TtyError> {
159         // TODO: 增加对EOF的处理
160         let mut cnt = 0;
161         while cnt < buf.len() {
162             let val: Result<mpsc::RecvRef<u8>, TryRecvError> = self.stdin_rx.try_recv_ref();
163             if let Err(err) = val {
164                 match err {
165                     TryRecvError::Closed => return Err(TtyError::Closed),
166                     TryRecvError::Empty => {
167                         if block {
168                             continue;
169                         } else {
170                             return Ok(cnt);
171                         }
172                     }
173                     _ => return Err(TtyError::Unknown(format!("{err:?}"))),
174                 }
175             } else {
176                 let x = *val.unwrap();
177                 buf[cnt] = x;
178                 cnt += 1;
179 
180                 if unlikely(self.stdin_should_return(x)) {
181                     return Ok(cnt);
182                 }
183             }
184         }
185         return Ok(cnt);
186     }
187 
188     fn stdin_should_return(&self, c: u8) -> bool {
189         // 如果是换行符或者是ctrl+d,那么就应该返回
190         return c == b'\n' || c == 4;
191     }
192 
193     /// @brief 向stdin缓冲区内写入数据
194     ///
195     /// @param buf 输入缓冲区
196     ///
197     /// @param block 当缓冲区满的时候,是否阻塞
198     ///
199     /// @return Ok(成功传送的字节数)
200     /// @return Err(BufferFull(成功传送的字节数)) 缓冲区满,成功传送的字节数
201     /// @return Err(TtyError) 内部错误信息
202     fn write_stdin(&self, buf: &[u8], block: bool) -> Result<usize, TtyError> {
203         let mut cnt = 0;
204         while cnt < buf.len() {
205             let r: Result<mpsc::SendRef<u8>, TrySendError> = self.stdin_tx.try_send_ref();
206             if let Err(e) = r {
207                 match e {
208                     TrySendError::Closed(_) => return Err(TtyError::Closed),
209                     TrySendError::Full(_) => {
210                         if block {
211                             continue;
212                         } else {
213                             return Err(TtyError::BufferFull(cnt));
214                         }
215                     }
216                     _ => return Err(TtyError::Unknown(format!("{e:?}"))),
217                 }
218             } else {
219                 *r.unwrap() = buf[cnt];
220                 cnt += 1;
221             }
222         }
223 
224         return Ok(cnt);
225     }
226 
227     /// @brief 读取TTY的output缓冲区
228     ///
229     /// @param buf 读取到的位置
230     /// @param block 是否阻塞读
231     ///
232     /// @return Ok(成功读取的字节数)
233     /// @return Err(TtyError) 内部错误信息
234     fn read_output(&self, buf: &mut [u8], block: bool) -> Result<usize, TtyError> {
235         let mut cnt = 0;
236         while cnt < buf.len() {
237             let val: Result<mpsc::RecvRef<u8>, TryRecvError> = self.output_rx.try_recv_ref();
238             if let Err(err) = val {
239                 match err {
240                     TryRecvError::Closed => return Err(TtyError::Closed),
241                     TryRecvError::Empty => {
242                         if block {
243                             continue;
244                         } else {
245                             return Ok(cnt);
246                         }
247                     }
248                     _ => return Err(TtyError::Unknown(format!("{err:?}"))),
249                 }
250             } else {
251                 buf[cnt] = *val.unwrap();
252                 cnt += 1;
253             }
254         }
255         return Ok(cnt);
256     }
257 
258     /// @brief 向output缓冲区内写入数据
259     ///
260     /// @param buf 输入缓冲区
261     ///
262     /// @param block 当缓冲区满的时候,是否阻塞
263     ///
264     /// @return Ok(成功传送的字节数)
265     /// @return Err(BufferFull(成功传送的字节数)) 缓冲区满,成功传送的字节数
266     /// @return Err(TtyError) 内部错误信息
267     fn write_output(&self, buf: &[u8], block: bool) -> Result<usize, TtyError> {
268         let mut cnt = 0;
269         while cnt < buf.len() {
270             let r: Result<mpsc::SendRef<u8>, TrySendError> = self.output_tx.try_send_ref();
271             if let Err(e) = r {
272                 match e {
273                     TrySendError::Closed(_) => return Err(TtyError::Closed),
274                     TrySendError::Full(_) => {
275                         if block {
276                             continue;
277                         } else {
278                             return Err(TtyError::BufferFull(cnt));
279                         }
280                     }
281                     _ => return Err(TtyError::Unknown(format!("{e:?}"))),
282                 }
283             } else {
284                 *r.unwrap() = buf[cnt];
285                 cnt += 1;
286             }
287         }
288 
289         return Ok(cnt);
290     }
291 
292     /// @brief 开启tty输入回显(也就是将输入数据传送一份到输出缓冲区)
293     #[inline]
294     pub fn enable_echo(&self) {
295         self.state.write().set(TtyCoreState::ECHO_ON, true);
296     }
297 
298     /// @brief 关闭输入回显
299     #[inline]
300     #[allow(dead_code)]
301     pub fn disable_echo(&self) {
302         self.state.write().set(TtyCoreState::ECHO_ON, false);
303     }
304 
305     /// @brief 判断当前tty核心,是否开启了输入回显
306     ///
307     /// @return true 开启了输入回显
308     ///
309     /// @return false 未开启输入回显
310     #[inline]
311     #[allow(dead_code)]
312     pub fn echo_enabled(&self) -> bool {
313         return self.state.read().contains(TtyCoreState::ECHO_ON);
314     }
315 }
316 
317 // ======= 以下代码考虑了“缓冲区满,然后睡眠,当缓冲区有空位就唤醒”的逻辑。
318 // 但是由于在开发过程中的调整,并且由于数据结构发生变化,因此暂时不实现上述优化,因此先注释。
319 //
320 // @brief 读取TTY的stdin缓冲区
321 //
322 // @param buf 读取到的位置
323 // @param block 是否阻塞读
324 //
325 // @return Ok(成功读取的字节数)
326 // @return Err(TtyError) 内部错误信息
327 // pub fn read_stdin(&mut self, buf: &mut [u8], block: bool) -> Result<usize, TtyError> {
328 //     let mut cnt = 0;
329 //     loop{
330 //         if cnt == buf.len(){
331 //             break;
332 //         }
333 //         let val:Option<u8> = self.stdin_queue.dequeue();
334 //         // 如果没读到
335 //         if val.is_none() {
336 //             // 如果阻塞读
337 //             if block {
338 //                 let state_guard: RwLockUpgradableGuard<TtyCoreState> =
339 //                     self.state.upgradeable_read();
340 //                 // 判断是否有进程正在stdin上睡眠,如果有,则忙等读
341 //                 // 理论上,这种情况应该不存在,因为stdin是单读者的
342 //                 if state_guard.contains(TtyCoreState::BLOCK_AT_STDIN_READ) {
343 //                     kwarn!("Read stdin: Process {} want to read its' stdin, but previous process {} is sleeping on the stdin.", current_pcb().pid, self.stdin_waiter.read().as_ref().unwrap().pid);
344 //                     drop(state_guard);
345 //                     Self::ringbuf_spin_dequeue(&mut buf[cnt], &mut self.stdin_queue);
346 //                     cnt += 1;
347 //                 } else {
348 //                     // 正常情况,阻塞读,将当前进程休眠
349 //                     let mut state_guard: RwLockWriteGuard<TtyCoreState> = state_guard.upgrade();
350 //                     let mut stdin_waiter_guard: RwLockWriteGuard<
351 //                         Option<&mut process_control_block>,
352 //                     > = self.stdin_waiter.write();
353 
354 //                     // 由于输入数据到stdin的时候,必须先获得state guard的读锁。而这里我们已经获取了state的写锁。
355 //                     // 因此可以保证,此时没有新的数据会进入stdin_queue. 因此再次尝试读取stdin_queue
356 //                     let val:Option<u8> = self.stdin_queue.dequeue();
357 //                     // 读到数据,不用睡眠
358 //                     if val.is_some(){
359 //                         buf[cnt] = val.unwrap();
360 //                         cnt += 1;
361 //                         continue;
362 //                     }
363 //                     // 没读到数据,准备睡眠
364 
365 //                     // 设置等待标志位
366 //                     state_guard.set(TtyCoreState::BLOCK_AT_STDIN_READ, true);
367 
368 //                     // 将当前进程标记为被其他机制管理
369 //                     unsafe {
370 //                         current_pcb().mark_sleep_interruptible();
371 //                     }
372 
373 //                     *stdin_waiter_guard = Some(current_pcb());
374 //                     drop(stdin_waiter_guard);
375 //                     drop(state_guard);
376 //                     sched();
377 //                     continue;
378 //                 }
379 //             } else {
380 //                 // 非阻塞读,没读到就直接返回了
381 //                 return Ok(cnt);
382 //             }
383 //         }else{
384 //             buf[cnt] = val.unwrap();
385 //             cnt += 1;
386 //         }
387 //     }
388 
389 //     return Ok(cnt);
390 // }
391 
392 // fn write_stdin(&self)
393 
394 // /// @brief 非休眠的,自旋地读队列,直到有元素被读出来
395 // fn ringbuf_spin_dequeue(dst: &mut u8, queue: &mut AllocRingBuffer<u8>) {
396 //     loop {
397 //         if let Some(val) = queue.dequeue() {
398 //             *dst = val;
399 //             return;
400 //         }
401 //     }
402 // }
403