Appearance
现实世界
与许多操作系统一样,Xv6 允许在内核中执行时发生中断甚至上下文切换(通过 yield
)。这样做的原因是在运行时间较长的复杂系统调用期间保持快速的响应时间。然而,如上所述,允许在内核中中断是一些复杂性的来源;因此,一些操作系统只允许在执行用户代码时中断。
要完全支持典型计算机上的所有设备是一项繁重的工作,因为设备众多,设备功能繁多,而且设备和驱动程序之间的协议可能复杂且文档记录不佳。在许多操作系统中,驱动程序占用的代码比核心内核还多。
UART 驱动程序通过读取 UART 控制寄存器一次一个字节地检索数据;这种模式称为编程 I/O(programmed I/O),因为软件正在驱动数据移动。编程 I/O 很简单,但速度太慢,无法用于高数据速率。需要高速移动大量数据的设备通常使用直接内存访问 (DMA)(direct memory access)。DMA 设备硬件直接将传入数据写入 RAM,并从 RAM 读取传出数据。现代磁盘和网络设备使用 DMA。DMA 设备的驱动程序会在 RAM 中准备数据,然后使用对控制寄存器的单次写入来告诉设备处理准备好的数据。
当设备在不可预测的时间需要关注,并且频率不高时,中断是有意义的。但中断的 CPU 开销很高。因此,高速设备,如网络和磁盘控制器,使用技巧来减少对中断的需求。一种技巧是为一批传入或传出的请求引发单个中断。另一种技巧是让驱动程序完全禁用中断,并定期检查设备以查看是否需要关注。这种技术称为轮询(polling)。如果设备以高速率执行操作,轮询是有意义的,但如果设备大部分时间处于空闲状态,则会浪费 CPU 时间。一些驱动程序根据当前的设备负载动态地在轮询和中断之间切换。
UART 驱动程序首先将传入数据复制到内核中的缓冲区,然后再复制到用户空间。这在低数据速率下是有意义的,但对于非常快速地生成或消耗数据的设备,这种双重复制会显著降低性能。一些操作系统能够直接在用户空间缓冲区和设备硬件之间移动数据,通常使用 DMA。
如第 1 章所述,控制台对应用程序显示为常规文件,应用程序使用 read
和 write
系统调用来读取输入和写入输出。应用程序可能希望控制无法通过标准文件系统调用表达的设备方面(例如,在控制台驱动程序中启用/禁用行缓冲)。Unix 操作系统为此类情况支持 ioctl
系统调用。
计算机的某些用法要求系统必须在有限的时间内做出响应。例如,在安全关键系统中,错过最后期限可能导致灾难。Xv6 不适用于硬实时设置。用于硬实时的操作系统往往是与应用程序链接的库,以便能够进行分析以确定最坏情况的响应时间。Xv6 也不适用于软实时应用程序,在这种应用程序中,偶尔错过最后期限是可以接受的,因为 xv6 的调度程序过于简单,并且其内核代码路径中中断被长时间禁用。