关于console的疑惑
我们知道当UART的缓冲区已满的时候,系统会sleep程序直到缓冲区里的东西被消费。于是我们开始疑惑,难道console只能输入不超过128(buffer),尝试了一下还真是,于是疑惑,为什么console的输出能超过128(因为报错的时候通常会打印很多字符)。
其实是因为输出的buffer被显示器消费了。
虽然你输入超过 128 个字符到控制台时,UART 的缓冲区(通常是有限的,比如 128 字符)可能已经满了,但这并不会阻止控制台输出超过 128 个字符。这是因为输入缓冲区和输出缓冲区是分开的,并且它们在操作系统的管理下以不同的方式工作。
1. 输入和输出的缓冲区是分开的
• 输入缓冲区:用户输入字符时,这些字符首先会被放入内核的输入缓冲区(如键盘缓冲区),在这个缓冲区满之前,用户可以继续输入。当缓冲区满时,系统会暂时停止接受更多输入,直到缓冲区中有数据被消费。
• 输出缓冲区:当用户输入的字符需要被打印到屏幕(即输出到控制台)时,字符会通过输出缓冲区进行处理,通常 UART 的输出缓冲区就是这个输出数据的缓冲区。
2. UART 中断处理和缓冲区的交互
在你输入字符并且这些字符最终输出到控制台时,操作系统会通过 UART 的中断处理机制来不断地将数据从缓冲区发送出去。
• 当 UART 输出缓冲区(tx 缓冲区)满了,程序会进入 sleep,等待 UART 中断处理将数据发送出去。UART 的发送速度相对较慢(尤其在波特率较低的情况下),因此系统使用缓冲区来缓冲需要发送的数据。
• 当 UART 发送完成一部分数据后,缓冲区会腾出空间,sleep 状态的进程就会被唤醒,继续往缓冲区写数据。
3. 循环缓冲区机制
xv6 的 UART 驱动使用循环缓冲区(ring buffer)。这意味着即便缓冲区大小有限(如 128 字符),它也能在不断消耗和腾出空间的过程中接收更多的数据。以下是大致的流程:
-
当缓冲区有空位时,producer 会写入字符到缓冲区。
-
UART 中断会不断从缓冲区读取数据并将其发送出去(打印到控制台)。
-
当数据发送出去后,缓冲区就会腾出空间,允许新的字符被写入。
因此,尽管缓冲区大小有限,UART 的持续传输过程让你感觉可以输入和输出超过 128 个字符。
4. 为什么控制台能输出 128 个字符以上?
• UART 中断服务:UART 通过中断机制将缓冲区的数据持续发送到控制台。即使你输入了超过 128 个字符,UART 通过中断处理会逐步将数据从缓冲区发送出去,腾出空间给新的数据。这就使得即使缓冲区有大小限制,系统依然可以处理并输出超过 128 个字符。
• 进程调度:当缓冲区满时,当前进程会 sleep,而操作系统调度其他进程(例如 uartintr())来处理输出。一旦缓冲区有空位,等待的进程会被唤醒继续写入。因此,你输入的字符被不断消费和输出,最终显示在控制台上。