设备控制器
Why?
鼠标、键盘、显示器、网卡、打印机、硬盘,多种多样的设备需要一个控制器来统一管理。CPU来管理效率太低。
How?
设备控制器有芯片和寄存器:
- 状态寄存器(Status Register):告诉CPU现在已经在工作或工作已经完成
- 命令寄存器(Command Register):记录CPU的命令,标记是否完成
- 数据寄存器(Data Register):暂存CPU向IO设备的写数据
输入输出设备分类:
-
块设备:数据存储在固定大小的块中,每个块有自己的地址,硬盘、USB 是常见的块设备。
- 数据量大,控制器设立了一个可读写的数据缓冲区,减少对设备的操作次数。
-
字符设备:以字符为单位发送或接收一个字符流,字符设备是不可寻址的,也没有任何寻道操作,鼠标是常见的字符设备。
CPU 与设备的控制寄存器和数据缓冲区的通讯方法:
- 端口 I/O:每个控制寄存器被分配一个 I/O 端口,可以通过特殊的汇编指令操作这些寄存器,比如 in/out 类似的指令。
- 内存映射 I/O:将所有控制寄存器映射到内存空间中,这样就可以像读写内存一样读写数据缓冲区。
I/O控制方式
Why?
设备控制器读完(完成任务)如何通知CPU?
How?
-
轮询等待(傻):CPU轮询读取状态寄存器
-
中断:硬件的中断控制器,当设备完成任务后触发中断到中断控制器,中断控制器就通知 CPU
- 软中断:例如代码调用 INT 指令触发
- 硬件中断:硬件通过中断控制器触发的。
DMA(Direct Memory Access)
Why?
CPU接收磁盘控制器的IO中断,将数据从磁盘缓冲区拷贝到PageCache,再拷贝到用户缓冲区
老是中断打断CPU也不好,特别是对于频繁读写数据的磁盘。
How?
对于读写类设备,在 CPU 不参与的情况下,DMA自行把设备 I/O 数据放入到内存。
- 相当于DMA代替CPU去接收一次次小中断,整个完成DMA再中断通知一次CPU
DMA 的工作方式:
-
CPU 需对 DMA 控制器下发指令,告知读取数据量以及内存位置;
-
DMA 控制器向磁盘控制器发出指令,通知它从磁盘读数据到其内部的缓冲区中,接着磁盘控制器将缓冲区的数据传输到内存;
-
磁盘控制器把数据传输到内存的操作完成后,磁盘控制器在总线上发出一个确认成功的信号到 DMA 控制器;
-
DMA 控制器收到信号后,DMA 控制器发中断通知 CPU 指令完成,CPU 就可以直接用内存里面现成的数据了;
设备驱动程序
Why?
设备控制器屏蔽了设备的众多细节,但每种设备的控制器的寄存器、缓冲区等使用模式都是不同的,所以为了屏蔽「设备控制器」的差异,引入了设备驱动程序,例如网卡驱动、显卡驱动。
相当于运行在CPU上与设备控制器打交道的软件。
How?
设备控制器虽然功能不同,但是设备驱动程序会提供统一的接口给操作系统
- 中断处理程序:处理并响应控制器发来的中断请求
中断处理程序的处理流程:
- 在 I/O 时,设备控制器如果已经准备好数据,则会通过中断控制器向 CPU 发送中断请求;
- 保护被中断进程的 CPU 上下文;
- 转入相应的设备中断处理函数;
- 进行中断处理;
- 恢复被中断进程的上下文;
通用块层
Why?
减少不同块设备的差异带来的影响,Linux 通过一个统一的通用块层,来管理不同的块设备。
How?
文件系统和磁盘驱动中间的一个块设备抽象层
- 向上为文件系统和应用程序,提供访问块设备的标准接口,向下把各种不同的磁盘设备抽象为统一的块设备,并在内核层面,提供一个框架来管理这些设备的驱动程序;
- 对文件系统和应用程序发来的 I/O 进行调度,提高磁盘读写的效率。
Linux 内存支持 5 种 I/O 调度算法:
-
没有:虚拟机 I/O
-
先入先出:
-
完全公平:默认,为每个进程维护了一个 I/O 调度队列,并按照时间片来均匀分布每个进程的 I/O 请求。
-
优先级:适用于运行大量进程的系统,像是桌面环境、多媒体应用等。
-
最终期限:分别为读、写请求创建了不同的 I/O 队列,这样可以提高机械磁盘的吞吐量,并确保达到最终期限的请求被优先处理,适用于在 I/O 压力比较大的场景,比如数据库等。
储系统I/O软件分层
- 文件系统层:包括虚拟文件系统和其他文件系统的具体实现,它向上为应用程序统一提供了标准的文件访问接口,向下会通过通用块层来存储和管理磁盘数据。
- 通用块层:包括块设备的 I/O 队列和 I/O 调度器,它会对文件系统的 I/O 请求进行排队,再通过 I/O 调度器,选择一个 I/O 发给下一层的设备层。
- 设备层:包括硬件设备、设备控制器和驱动程序,负责最终物理设备的 I/O 操作。
缓存机制
- 提高文件访问的效率:页缓存、索引节点缓存、目录项缓存等,减少对块设备的直接调用。
- 提高块设备的访问效率:使用缓冲区来缓存块设备的数据。
键盘敲入字母时,期间发生了什么?
-
键盘控制器就会产生扫描码数据,并将其缓冲在键盘控制器的寄存器中,通过总线给 CPU 发送中断请求。
-
CPU 收到中断请求后,操作系统会保存被中断进程的 CPU 上下文,然后调用键盘的中断处理程序。
-
键盘中断处理函数从键盘控制器的寄存器的缓冲区读取扫描码翻译成对应显示字符的 ASCII 码放到「读缓冲区队列」
-
显示设备的驱动程序会定时从「读缓冲区队列」读取数据放到「写缓冲区队列」,最后把「写缓冲区队列」的数据一个一个写入到显示设备的控制器的寄存器中的数据缓冲区,最后将这些数据显示在屏幕里。
磁盘调度算法⭐
What?
- 盘片:一个盘
- 磁道:盘片上半径相同的原形为一个磁道
- 扇区:一段磁道,512KB
- 柱面:多个具有相同编号的磁道形成一个圆柱,相当于纵向的看
Why?
磁盘机械寻道速度慢,应该尽可能减少寻道时间。
How?
优化磁盘的访问请求顺序:
-
先来先服务:性能差
-
最短寻道时间优先:贪心,会产生饥饿
-
扫描算法SCAN:像雨刮器,磁头在一个方向上移动,访问所有未完成的请求,直到磁头到达该方向上的最后的磁道,才调换方向
- 性能好,无饥饿,但是两端响应频率低
-
循环扫描算法C-SCAN:磁道只响应一个方向上的请求,然后再返回开始位置
- 对于各个位置磁道响应频率相对比较平均
-
LOOK 与 C-LOOK 算法:磁头在移动到「最远的请求」位置,然后立即反向移动。
- 扫描、循环扫描:磁头移动到磁盘「最始端或最末端」才开始调换方向。