init_IRQ()
set_intr_gate
设置中断处理例程为:push $vector;
jmp common_interrupt;
common_interrupt
SAVE_ALL
do_irq
irq_enter
if(需要切换堆栈)
切换堆栈
desc->handle_irq(如:8259A,在init_IRQ中通过set_irq_chip_and_handler_name函数把handle_irq设置为handle_level_irq)
handle_level_irq()
mask_ack_irq(向中断控制器发出中断应答,并通知中断控制器屏蔽这条中断请求线,对于某些多处理器来水,该行仅在当前CPU上屏蔽该中断)
handle_IRQ_event
do
{
action->handler();
action=action->next;
}
while(action)
if(需要切换堆栈)
切换堆栈
irq_exit
do_softirq
__do_softirq
jmp ret_from_intr
1 处理延迟的调度请求
这里通过一个例子更容易理解,假设有ph和pl两个进程,进程ph优先级大于pl,现在ph通过系统调用(比如sys_read),进入内核态,它进行磁盘IO操作,但磁盘缓存队列中没有现成的数据,于是磁盘磁盘驱动程序向磁盘发出读请求,此时进程ph主动放弃CPU,进入等待队列。然后进程pl被调度运行,片刻后,磁盘完成读操作并向CPU发出中断,磁盘中断服务历程通知调度器把进程ph重新加入就绪队列,调度器此时发现就绪队列中ph的优先级大于当前进程pl,于是请求调度ph。但是延迟到中断处理结束。此时pl没有主动放弃CPU,而是被进程ph抢占了cpu资源。进程ph的调度时机分为以下两种情况:
1)中断发生时,pl运行在用户态环境,此时中断处理结束后,在返回进程pl用户态前,内核检查到这个延迟的调度请求,于是通知调度器重新调度。调度器根据调度算法选择进程ph运行。
如果是在中断处理过程中发生了异常,而异常处理程序也会走到这段代码,并且异常处理程序可能已经修复了这个异常,此时被你异常中断的中断处理程序更为紧急,所以这种情况下,先不处理延迟的调度,等中断处理返回时在处理这个延迟的调度。
2)中断发生时,pl运行在内核态,此时如果内核在编译时配置了CONFIG_PREEMPT,则直接通知调度器重新调度,如果没有,则不允许在内核态发生抢占。于是恢复中断现场,返回进程pl的内核态继续运行。当进程pl在内核态因请求某种资源得不到满足而主动放弃CPU,或者进程pl要返回用户空态前时,这个延迟的请求调度才会被处理。
2 延迟的信号处理。
3 vm86模式处理。