Linux内核设计与实现——中断和中断处理
2018-04-25 本文已影响68人
leon4ever
操作系统的核心任务,包含对硬件设备的有效管理,为了避免轮询(周期性检查),通过中断机制,即硬件在需要的时候向内核发出信号。
1.中断
硬件——电信号——中断控制器——处理器
每个中断有唯一的数字标志
异常:处理器执行时产生错误指令(除0)或者特殊情况(缺页)等,必须依靠内核来处理的时候,处理器回产生一个异常
2. 中断处理程序
响应特定中断时,会通过中断向量表找到一个对应的中断处理程序,被内核调用来响应中断的,运行于中断上下文的特殊上下文中。
3. 上半部与下半部的对比
中断处理程序要快! VS 中断处理程序完成的工作量多!
把中断处理切为两个部分,
- 上半部是接收到中断就立即执行,但是只做有严格时限的工作
- 能够允许稍后完成的工作会推迟到下半部,在合适的时机,下半部会开中断执行
4. 注册中断处理程序
/*
* irg - 表示要分配的中断号
* handler - 实际的中断处理程序
* flags - 标志位,表示此中断的具有特性
* name - 中断设备名称的ASCII 表示,这些会被/proc/irq和/proc/interrupts文件使用
* dev - 用于共享中断线,多个中断程序共享一个中断线时(共用一个中断号),依靠dev来区别各个中断程序
* 返回值:
* 执行成功:0
* 执行失败:非0
*/
int request_irq(unsigned int irq,
irq_handler_t handler,
unsigned long flags,
const char* name,
void *dev)
释放中断处理程序:
void free_irq(unsigned int irq, void *dev)
5. 中断上下文
当执行一个中断处理程序的时候,内核处于中断上下文,与进程没啥关系,没有后备进程,所以不可以睡眠。
中断处理程序打断了其它的代码(甚至可能打断另一中断处理程序,以及软中断),所以必须快速,简洁
6. 中断处理机制的实现
如图
中断处理机制.png
ret_from_intr负责检查重新调度是否正在挂起,如果返回用户空间(也就是说中断的是用户空间),那么schedule()被调用,如果返回内核空间(中断的是内核本身),只有preempt_count为0时,schedule()才会被调用,否则抢占内核是不安全的。
7. 中断控制
控制中断是因为需要提供同步,通过禁止中断,可以确保某个中断处理程序不会抢占当前的代码,还可以禁止内核抢占。
同时,还需要保护机制来防止来自其他处理器的并发访问,内核代码一般都需要锁,伴随着禁止本地中断。
其实就是禁止中断提供保护机制,防止来自其他中断处理程序的并发访问。
函数 | 说明 |
---|---|
local_irq_disable() | 禁止本地中断传递 |
local_irq_enable() | 激活本地中断传递 |
local_irq_save() | 保存本地中断传递的当前状态,然后禁止本地中断传递 |
local_irq_restore() | 恢复本地中断传递到给定的状态 |
disable_irq() | 禁止给定中断线,并确保该函数返回之前在该中断线上没有处理程序在运行 |
disable_irq_nosync() | 禁止给定中断线 |
enable_irq() | 激活给定中断线 |
irqs_disabled() | 如果本地中断传递被禁止,则返回非0;否则返回0 |
in_interrupt() | 如果在中断上下文中,则返回非0;如果在进程上下文中,则返回0 |
in_irq() | 如果当前正在执行中断处理程序,则返回非0;否则返回0 |