Linux源码阅读 - 近水楼台
Linux中断处理
基于内核2.4.0,硬件i386
基本处理
下图为硬件在接收到中断的时候(未被屏蔽),响应中断请求,寻找中断服务程序的过程。
基于这样的硬件服务,操作系统要做的就是:
编制中断处理程序或者提供用户登记其中断服务程序的机制
初始化中断向量表IDT
void __init trap_init(void)
void __init init_IRQ(void)
加载IDT
ldtr
外部中断的处理与中断请求队列
I386系统结构支持256个中断向量,扣除一些为CPU本身保留的向量,剩下的可能不够用。
那么很多外部设备就不得不共用中断向量
Linux的处理方法就是:
系统为每个中断向量设置一个队列
设置数组irq_desc[],其中每个元素为这样一个队列 的头部以及控制结构。
当中断发生时,首先执行与中断向量相对应的一段总服务程序,
根据中断源的设备号在其所属队列中找其对应的服务程序加以执行。
下图为其中数据结构的指向流图,也表明了些函数调用的过程。
中断处理过程:
外部中断处理函数的入口
IRQ0xY_interrupt:
总服务程序
common_interrupt:
执行跟中断向量相关的控制,调用中断处理函数
do_IRQ(struct pt_regs regs)
处理中断
handle_IRQ_envent(unsigned irq, struct pt_regs *regs, struct irqaction *action)
其中中断请求队列的初始化:
数组
extern irq_desc_t irq_desc[NR_IRQ]
数组初始化
void __init init_ISA_irqs(void)
设备向系统登记其中断服务程序
int request_irq(unsigned int irq,
void (*handler)(int, void*, struct pt_regs),
unsigned long irqflags,
const char * devname,
void *dev_id)
将action链入相应的中断请求队列
setup_irq(unsigned int irq, struct irqactiong *new)
软中断与bottom half
中断服务一般都是在关中断条件下执行,但是入关关中断时间太长可能因为CPU不能及时响应其他中断而使中断请求丢失。
操作系统都把中断分成了两个部份,上半部份与下半部份。上半部份通常是响应中断,并把中断所得到的数据保存进下半部。
耗时的操作一般都会留到下半部去处理。后半部分即bottom half,简称bh。
软中断通常是硬中断服务程序对内核的中断。它利用硬件中断的概念,用软件方式进行模拟,实现宏观上的异步执行效果。
Linux用软中断机制实现bh。
一些数据结构:
关于软中断
向量表
static struct softirq_action soft_vec[32]
软中断请求寄存器(某个软中断向量上有了请求,相应位置1)
__soft_active
软中断屏蔽寄存器
__soft_mask
基于tasklet
struct tasklet_struct bh_task_vec[32]
bh函数数组
bh_base[32]
下以时钟中断为例说明用软中断实现bh的过程。
下图详述了各个数据结构初始化的过程以及bh实现的函数调用过程。
说明
bh实现的函数调用过程:
响应软中断
在do_IRQ()执行完一个通道中的中断服务程序后以及在每当从系统 调用返回时,调用do_softirq()
进入do_softirq()
通过softirq_active和softirq_mask的标志位确定哪个软中断向量提出了软中断请求需要处理,
调用软中断处理函数soft_vec[i]->action(h)
软中断处理函数tasklet_hi_action()
访问当前cpu的tasklet_hi_vec[cpu],根据此链表访问bh_task_vec[i],
调用bh_task_vec[i]->action(data)
执行bh_action()
访问bh_base[]数组,依次执行存在的bh函数
执行bh_action()
各个数据结构的初始化
软中断向量表soft_vec[]
softirq_init()->open_softirq()
bh_task_vec[]初始化
softirq_init()->tasklet_init()
bh_task_vec[]链接到tasklet_hi_vec[cpu]
mark_bh()->task_hi_schedule()
bh_base[]置值
init_bh()
以上为看了Linux内核情景分析中断异常这一章做的一个小结。仅述了一个基本的逻辑过程,细节方面没作详述。