前言
CPU 拷贝:
由 CPU 直接处理数据的传送,数据拷贝时会一直占用 CPU 的资源。
DMA 拷贝:
由 CPU 向DMA磁盘控制器下达指令,让 DMA 控制器来处理数据的传送,数据传送完毕再把信息反馈给 CPU,从而减轻了 CPU 资源的占有率。
上下文切换:
-
当用户程序向内核发起系统调用时,CPU 将用户进程从用户态切换到内核态;
-
当系统调用返回时,CPU 将用户进程从内核态切换回用户态。
网络 I/O
磁盘 I/O
读操作
当应用程序执行 read 系统调用读取一块数据的时候,如果这块数据已经存在于用户进程的页内存中,就直接从内存中读取数据。
如果数据不存在,则先将数据从磁盘加载数据到内核空间的读缓存(Read Buffer)中,再从读缓存拷贝到用户进程的页内存中。
read(file_fd, tmp_buf, len)
:基于传统的 I/O 读取方式,read 系统调用会触发 2 次上下文切换,1 次 DMA 拷贝和 1 次 CPU 拷贝。
发起数据读取的流程如下:
-
用户进程通过 read 函数向 Kernel 发起 System Call,上下文从 user space 切换为 kernel space。
-
CPU 利用 DMA 控制器将数据从主存或硬盘拷贝到 kernel space 的读缓冲区(Read Buffer)。
-
CPU 将读缓冲区(Read Buffer)中的数据拷贝到 user space 的用户缓冲区(User Buffer)。
-
上下文从 kernel space 切换回用户态(User Space),read 调用执行返回。
传统CPU存取数据
因为CPU 的工作速度和外设的工作速度差距太大,且外设格式种类繁多,无法直接存取,需要经过转换,因此CPU 不直接存取外设
。
基于上述原因,传统CPU 获取数据的步骤如下:
-
CPU 将外设数据加载到内存(和CPU的处理速度最接近)
-
CPU 检查 cache 是否有自己需要的数据(是否命中)
-
如果命中,直接返回数据;如未命中,继续从内存获取(这里暂时不考虑MMU)
-
返回数据
详细图示:
可以看到整个数据传输的过程:
- 首先在用户进程进行read()系统调用的时候,操作系统会由用户态切换到内核态,然后由CPU向磁盘发起IO请求。
- 磁盘在接收到IO请求以后,进行数据准备工作,将数据放在磁盘控制器缓冲区里。
- 在数据准备工作完成以后,磁盘向CPU发出IO中断信号。
- CPU收到中断信号后,会先将磁盘缓冲区中的文件copy到PageCache中,再将数据从PageCache中copy到用户缓冲区中。在这期间CPU是无法执行其他任务的。copy完成之后read()调用返回,操作系统刚从内核态切换回用户态。
故可以得知:在数据传输的过程,需要CPU亲自的去拷贝数据,并且在这期间CPU无法去做其他事情。简单的搬运几个字符没有问题,但是当处理大量数据的时候,如果每次都让CPU来搬运,显然忙不过来。
DMA
传统CPU 读取数据无论是将外设数据搬移到内存,还是从内存读取数据,都需要CPU 的参与。为了让 CPU 能够专注于处理手中事务,DMA 将负责数据的搬移工作。
DMA(Direct Memory Access)即直接存储器访问,借助内部的控制器来实现内存和外设之间的数据传输。有了DMA,CPU 可以专注于内存数据的存取;数据的搬运过程完全可以交由DMA硬件完成。有了DMA以后,不代表完全不需要CPU了,只是不会像中断那样频繁向CPU发送请求。
开始传输时刻
:DMA向CPU申请至少一个总线周期的占用时间来做数据传输工作结束传输时刻
:DMA向CPU发送中断请求,请求CPU处理这些数据
详细图示:
-
当有了DMA控制器以后,在进程向CPU发出read()调用以后,CPU向DMA控制器发起IO请求,然后DMA控制器再向磁盘发出IO请求。
-
当磁盘接收到IO请求以后,会进行数据准备工作,将数据放到磁盘数据缓冲区当中。
-
当磁盘的数据准备工作完成以后,不再向CPU发出中断信号,而是通知DMA控制器。
-
DMA控制器在接收到通知以后,将数据从磁盘控制器缓冲区中copy到内核缓冲区中。在这期间并不占用CPU,CPU可以处理其他的事情,执行其他的任务。
-
DMA控制器处理完之后向CPU发出中断信号,由CPU将数据从内核缓冲区copy至用户缓冲区中。copy完成之后read()调用返回,操作系统从内核态切换回用户态。
注意:起初的DMA控制器只在主板上,但是现在IO设备越来越多,数据传输的需求也不尽相同,所以现在每个IO设备中都有DMA控制器。
DMA工作模式
-
直接模式
DMA 直接进行从源地址到目的地址的数据传输。 -
FIFO 模式
。
FIFO模式下,可以将要传输的多个数据(或字节)累计存储在FIFO缓冲器中,然后在FIFO缓冲器中设置存储阈值,当到达阈值时,FIFO会自动把所有存储的数据一次性的发送到目标地址。
DMA数据传输方式:
单字传送(单次模式)
DMA 请求获得批准后,CPU 让出一个总线周期用于字或字节的传送。结束后, DMA 控制器归还总线控制权,CPU 再重新判断下一个总线周期的总线控制权是 CPU 保留,还是继续响应一次新的 DMA 请求。这种方式称为单字传送方式,又称为周期挪用或周期窃取。块传送(突发模式)
DMA 请求获得批准后,DMA 控制器掌管总线控制权,连续占用若干个总线周期,进行成组连续的批量传送,直到批量传送结束,才将总线的控制权交还给 CPU。这种方式称为成组连续传送方式
寻址模式:
-
增量寻址:发送完数据后,继续发送下一个地址的数据,配合突发传输模式
-
非增量寻址: 一发送完数据后,如果想要继续发送数据,需要更具软件配置的发送下一个数据的地址,再进行数据的传输
DMA 数据传输步骤
数据传输流程图:
一、准备阶段
CPU 会对 DMA 控制器和 IO 接口进行初始化,初始化的内容如下:
-
DMA 控制器初始化
- 配置 DMA 内存缓冲区的首地址(即告诉DMA把数据放到哪)
- 配置 DMA 传输方向(是向外设传数据,还是从外设读数据)
- 配置 DMA 交换量(设置数据传输的上限)
-
接口的初始化
- I/O 设备的寻址信息
二、传输请求
-
设备接口 => DMA 控制器
设备接口向DMA控制器发送 “ DMA请求 ” ,即请求使用 DMA 进行数据传输 -
DMA 控制器 => CPU
DMA 控制器向CPU申请 “ 总线占用 ”,DMA控制器和 CPU 只能有一个占用总线 -
CPU => DMA 控制器
CPU 批准使用总线,此时CPU会让出一个或者多个总线周期用于数据传输。在DMA数据传输期间,CPU 停止访问内存,无法执行需要占用总线的指令。 -
DMA 控制器 => 设备接口
DMA 批准设备请求,此时 DMA控制器将掌握总线控制权。如果是单字节传送,一个总线周期后,DMA归还总线控制权;如果是块传送,连续占用若干个总线周期后,DMA才会归还总线控制权。
三、数据传送
数据传送期间,DMA 控制器会向总线发送读/写命令、向 I/O 接口发响应信号。真正的数据交互是内存和设备接口,DMA 控制器只是负责控制整个数据传送流程。
四、善后处理
在初始化时,CPU 便指定了DMA的交换量,而且DMA 控制器内部有一个计数器,只有 DMA 控制器知道传送是否结束。当传送结束时,DMA控制器向CPU发送一个传输完成的中断,CPU重新接管总线的控制权。
注意:DMA 控制器并非只有在传输完成时才会发送中断,其实传输过半、传输错误也可以发送中断
DMA的双面性特点:对于CPU,DMA是外设;对于外设,DMA是控制器
为什么要使用DMA
第一,可以把比较固定的任务让DMA来做,可以减轻CPU负担,提高系统的效率;
第二,DMA具有一般CPU没有的高效操作,能够提高系统的吞吐率(IO 效率);
硬中断软中断
一、硬中断
由与系统相连的外设(比如网卡、硬盘)自动产生的,主要是用来通知操作系统系统外设状态的变化。
可屏蔽中断 ——当 CPU 接收到更高优先级的中断时,这些中断可以被延迟。
不可屏蔽中断 ——无法延迟这些中断。 CPU 应该立即考虑它们。
二、软中断
为了满足实时系统的要求,中断处理应该是越快越好。linux为了实现这个特点,当中断发生的时候,硬中断处理那些短时间就可以完成的工作,而将那些处理事件比较长的工作,放到中断之后来完成,也就是软中断(softirq)来完成。
三、区别
- 引发对象:硬中断是由外设引发的,软中断是执行中断指令产生的,无需外部施加中断请求信号。
- 提供中断号:硬中断的中断号是由中断控制器提供的,软中断的中断号由指令直接指出,无需使用中断控制器。
- 耗时:硬中断处理程序要确保它能快速地完成任务,这样程序执行时才不会等待较长时间,称为上半部。软中断处理硬中断未完成的工作,是一种推后执行的机制,属于下半部。
硬中断(Hardware Interrupts)是由外部设备发起的,通常用于表示设备需要CPU的注意,例如I/O操作完成、定时器中断等。硬中断通常是可屏蔽的,这意味着在处理某个硬中断过程中,CPU可以禁止响应其他硬中断,以防止嵌套中断带来的问题。当然,也有一些特定情况下的硬中断是不可屏蔽的,例如非屏蔽中断(Non-Maskable Interrupt, NMI)。
软中断(Software Interrupts)则是由软件主动触发的,通常用于实现系统调用、异常处理等。软中断的可屏蔽性取决于具体实现和系统需求。在某些情况下,软中断可能是不可屏蔽的,以确保某些关键任务或异常处理能够得到优先执行。然而,在其他情况下,软中断可能是可以屏蔽的,以避免嵌套中断或提高系统性能。