系统调用同步的激活内核,而中断是另一种激活内核的异步方式;
中断分类:硬件中断:外设自动产生,用于更高效实现设备驱动程序,和处理器对自身异常和错误的关注,这些需要和内核代码进行交互;
软中断:有效时限内核中的延期操作;
用于处理中断和系统调用的相关代码中,汇编和C代码交织在一起;内核需要一些机制,将某些活动延迟到未来的某个时间执行,或将活动置于某个队列上,在时间充裕时进行后续的处理;
linux2.6内核,引入一个中断和IRQ的通用框架;各个平台现在只负责在对底层上进行硬件交互;
另种中断的提法:同步中断和异常:CPU自身产生;产生异常---内核通知---应用程序,可以使用信号机制通知,应用程序---1 修改错误,2 输出适当的错误信息,3 直接结束; 内核必须和CPU进行交互;
异步中断:外部设备产生,可在任意时刻,不与特定进程关联;
不同的部分:不同的中断,可能对于是否在执行过程中禁用中断,会有不同的过程;
内核试图避免禁用中断,这样显然会损害系统性能;但这样可能产生严重的死锁问题;
选择结果:性能关键的前一部分在禁用中断时执行;不重要的部分延期执行,进行所有的次要操作;
不同的异常产生不同的编号,通过不同的编号来标识异常;liunx有32个异常编号;
同样,中断编号的数目有限,所以很多设备共享中断:共享中断的条件:硬件和内核同时支持该技术,通过中断编号和设备标识符来确定具体设备发生的中断;
硬件中断:外部设备---发送中断---中断控制器---发送中断请求(IRQ)----CPU中断输入
处理中断:软件例程:1 修复故障,2 提供专门处理, 3 将外部事件通知用户进程; 内核使用一个数组,数组项指向处理程序函数的指针,相关的中断号根据数组中的 位置判断;
中断处理划分为3个部分:1 建立一个适合的环境(进入路径);2 调用处理程序自身;3 系统恢复到中断之前的状态(退出路径);
进入:1 用户态栈切换到核心态栈;2 保存用户程序的当前寄存器状态,平台相关(不同CPU)的数据结构pt_regs列出了核心态可能修改的所有寄存器,利用汇编语言底层例程填充该结构;
退出:内核会检查2项:1 调度器是否选择新的进程代替旧进程;2 是否有信号投递到原进程;3 恢复寄存器集合;4 切换到用户态,激活用户栈;
不同空间的切换需要C代码和汇编代码的交互,小心处理,利用各个处理器的具体特征,正确设计两种语言之间的数据交换;
调用中断处理程序:ISR必须满足2个条件:1 实现必须包含尽可能少的代码,以支持快速处理;2 在执行期间调用其他ISR,不能彼此干扰;
ISR可以划分为3个部分:1 关键操作必须在中断后立即执行,必须禁用其他中断;2 非关键操作也应尽快执行,但允许启用中断;
3 可延期操作,不必在中断处理程序中实现,可在时间充裕时进行;内核提供的是tasklet;
中断的数据结构:中断实现的两个方面:1 与处理器高度相关,用于底层细节,汇编代码实现;2 抽象接口,是驱动程序和内核安装管理IRQ处理程序所需的;
内核必须为每个潜在的IRQ提供一个函数,必须能够动态注册和注销;IRQ相关信息管理关键:一个全局数组,每个数组项对应一个IRQ编号,且数组位置和中断号相同,中断号的最大数目和特定的硬件平台相关;
linux2.6内核中断处理子系统各部分及交互方式
2 中断电流处理:处理不同的中断电流类型之间的各种差别,边沿触发和电平触发;会涉及到大量体系结构相关的代码;
3 芯片级硬件封装:需要与产生中断的底层硬件直接通信,该抽象层可视为中断控制器的某种设备驱动程序;
初始化和分配IRQ: 1 注册IRQ,设备驱动程序动态注册IRQ,request_irq;
2 释放IRQ:跟注册相反:1 通过硬件相关的函数chip->shutdown通知中断控制器---IRQ已删除,利用free_irq函数删除相关数据项;
3 注册中断: 内核2种方式响应中断:1 向当前用户进程发送一个信号,通知有错误发生;2 内核自动修复错误,用户进程不可见,如缺页异常;
处理IRQ:1 切换到核心态,找到各个入口点;2 IRQ栈;3 调用电流处理程序例程;4 调用高层IRQ;
5 实现处理 程序例程;实现ISR时,主要的问题是中断上下文中执行;内核提供了in_interrupt函数来指明当前是否在处理中断;
中断上下文和普通上下文3点不同:1 中断是异步执行的,禁止访问用户空间;2 不能调用调度器,不能自愿放弃控制权;3 不能进入睡眠状态,调用 的所有过程和函数都不能进入睡眠状态;
软中断: