#define DECREMENTER_EXCEPTION \
START_EXCEPTION(Decrementer) \
NORMAL_EXCEPTION_PROLOG; \
lis r0,TSR_DIS@h; /* Setup the DEC interrupt mask */ \
mtspr SPRN_TSR,r0; /* Clear the DEC interrupt */ \
addi r3,r1,STACK_FRAME_OVERHEAD; \
EXC_XFER_LITE(0x0900, timer_interrupt)
void timer_interrupt(struct pt_regs * regs)
=>int cpu = smp_processor_id();
=>if (atomic_read(&ppc_n_lost_interrupts) != 0)//如果还有未处理的外部中断处理函数,则处理
do_IRQ(regs);
=>old_regs = set_irq_regs(regs);//保存寄存器现场,注意old_regs是指针,指向现场全局寄存器的指针
=>struct pt_regs *old_regs, **pp_regs = &__get_cpu_var(__irq_regs);//保存在__irq_regs全局变量里面,每个核一个
old_regs = *pp_regs;
*pp_regs = new_regs;
return old_regs
=>irq_enter();//中断计数加一,进入中断上下文
=>while ((ticks = tb_ticks_since(per_cpu(last_jiffy, cpu))) >= tb_ticks_per_jiffy)
per_cpu(last_jiffy, cpu) += tb_ticks_per_jiffy;
account_process_time(regs);//#define account_process_time(regs) update_process_times(user_mode(regs))
=>scheduler_tick();//选择合适的进程,用于时钟中断返回继续调度
=>curr->sched_class->task_tick(rq, curr);//.task_tick = task_tick_fair
=>struct sched_entity *se = &curr->se;
=>for_each_sched_entity(se) {
cfs_rq = cfs_rq_of(se);
entity_tick(cfs_rq, se);
}
if (cpu != boot_cpuid)
continue;
tb_next_jiffy = tb_last_jiffy + tb_ticks_per_jiffy;
if (per_cpu(last_jiffy, cpu) >= tb_next_jiffy) {
tb_last_jiffy = tb_next_jiffy;
do_timer(1);
timer_recalc_offset(tb_last_jiffy);
timer_check_rtc();
}
=>next_dec = tb_ticks_per_jiffy - ticks;
=>set_dec(next_dec);//设置DEC寄存器,用于触发下一次的时钟中断
=>irq_exit();
=>set_irq_regs(old_regs);
如下两个人的博客都挺好的
时钟中断(1)
https://blog.youkuaiyun.com/wrx1721267632/article/details/50527595
把握linux内核设计思想(六):内核时钟中断
https://blog.youkuaiyun.com/shallnet/article/details/47132861
[收藏]时钟中断(Timer Interrupt)与 Linux内核调度
https://blog.youkuaiyun.com/don_chiang709/article/details/89181399