# 5.5 真实世界

Xv6允许在内核中执行时以及在执行用户程序时触发设备和定时器中断。定时器中断迫使定时器中断处理程序进行线程切换（调用`yield`），即使在内核中执行时也是如此。如果内核线程有时花费大量时间计算而不返回用户空间，则在内核线程之间公平地对CPU进行时间分割的能力非常有用。然而，内核代码需要注意它可能被挂起（由于计时器中断），然后在不同的CPU上恢复，这是xv6中一些复杂性的来源。如果设备和计时器中断只在执行用户代码时发生，内核可以变得简单一些。

在一台典型的计算机上支持所有设备是一项艰巨的工作，因为有许多设备，这些设备有许多特性，设备和驱动程序之间的协议可能很复杂，而且缺乏文档。在许多操作系统中，驱动程序比核心内核占用更多的代码。

UART驱动程序读取UART控制寄存器，一次检索一字节的数据；因为软件驱动数据移动，这种模式被称为程序I/O（Programmed I/O）。程序I/O很简单，但速度太慢，无法在高数据速率下使用。需要高速移动大量数据的设备通常使用直接内存访问（DMA）。DMA设备硬件直接将传入数据写入内存，并从内存中读取传出数据。现代磁盘和网络设备使用DMA。DMA设备的驱动程序将在RAM中准备数据，然后使用对控制寄存器的单次写入来告诉设备处理准备好的数据。

当一个设备在不可预知的时间需要注意时，中断是有意义的，而且不是太频繁。但是中断有很高的CPU开销。因此，如网络和磁盘控制器的高速设备，使用一些技巧减少中断需求。一个技巧是对整批传入或传出的请求发出单个中断。另一个技巧是驱动程序完全禁用中断，并定期检查设备是否需要注意。这种技术被称为轮询（polling）。如果设备执行操作非常快，轮询是有意义的，但是如果设备大部分空闲，轮询会浪费CPU时间。一些驱动程序根据当前设备负载在轮询和中断之间动态切换。

UART驱动程序首先将传入的数据复制到内核中的缓冲区，然后复制到用户空间。这在低数据速率下是可行的，但是这种双重复制会显著降低快速生成或消耗数据的设备的性能。一些操作系统能够直接在用户空间缓冲区和设备硬件之间移动数据，通常带有DMA。