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