驱虫日志:控制台异常输入
现象描述:
- c
#include <stdlib.h> #include <stdio.h> int main() { char *s = malloc(1024); scanf("%s", s); printf("%s", s); } ``` - StarryOS多次运行用户态程序,类似上述代码之时,会因为一些控制台输入问题导致重复第一次的输入。
bash
starry:# ./a.out
first
first
starry:# ./a.out
second
first- 但是使用pipe传递给程序的时候被证明是正确的,将问题确认在控制台输入处
解决问题
- 全局的tty设备为一个全局静态单例,所有进程应该是共享这一实例
rust
lazy_static! {
/// The default TTY device.
pub static ref N_TTY: Arc<NTtyDriver> = new_n_tty();
}- 追溯一下NTtyDriver应该是一个Tty,根据已有信息可以直接排查TtyRead
rust
impl<R: TtyRead, W: TtyWrite> InputReader<R, W> {
//注意这个函数
pub fn poll(&mut self) -> bool {
if self.read_range.is_empty() {
let read = self.reader.read(&mut self.read_buf);
self.read_range = 0..read;
}
}- poll是负责从底层控制台读取原始字节的函数
- 此处仅当
read_range为空(上次读取的数据已全部处理完)时才读取(调用reader.read,最底层调用为console::read_byte)
- 此处仅当
- 那么下面一个分句中介绍了line_read是是否完成一行的读取,offset是用来判断读取的偏移是否已经达到这一行的末位,即本行是否完成。但是这里仅将line_read标志位置为0,没有清空buff,而buff仅在满了之后清空,所以会出现第二次调用的时候从头开始读取,还是第一次的缓存的效果
rust
if let Some(offset) = &mut self.line_read {
let read = self.buf_tx.push_slice(&self.line_buf[*offset..]);
if read == 0 {
break;
}
sent += read;
*offset += read;
if *offset == self.line_buf.len() {
self.line_read = None;
self.line_buf.clear(); // 新加入,用于清空
}
continue;
}