Windows系统会在初始化的时候将时钟中断与时钟中断处理函数进行关联,而正是在这个中断函数会在合适的时机进行系统的线程调度。
阶段1函数HalpInitPhase0会调用HalpEnableInterruptHandler函数开启时钟中断。HalpEnableInterruptHandler函数会在内部将时钟处理函数HalpClockInterrupt设置到相应的中断向量当中。HalpClockInterrupt在汇编文件中以宏的形式生成。
TRAP_ENTRY HalpClockInterrupt, KI_PUSH_FAKE_ERROR_CODE
TRAP_ENTRY实现中断处理的两个部分,第一部分生成一个中断框架,第二部分进行中断处理函数的调用。而真正的中断处理函数是通过宏调用组合而成的。在这里是HalpClockInterruptHandler函数。
MACRO(TRAP_ENTRY, Trap, Flags)
EXTERN @&Trap&Handler@4 :PROC
PUBLIC _&Trap
.PROC _&Trap
/* Generate proper debugging symbols */
FPO 0, 0, 0, 0, 1, FRAME_TRAP
/* Common code to create the trap frame */
KiEnterTrap Flags
/* Call the C handler */
KiCallHandler @&Trap&Handler@4
.ENDP
ENDM
在HalpClockInterruptHandler函数只有一个参数,就是中断的框架。在中断处理函数当中对这个参数进行一些设置之后,就需要对时钟的寄存器进行一些设置,然后传递给KeUpdateSystemTime。主要的中断操作都在KeUpdateSystemTime函数里面实现。
VOID
FASTCALL
HalpClockInterruptHandler(IN PKTRAP_FRAME TrapFrame)
{
ULONG LastIncrement;
KIRQL Irql;
/* Enter trap */
KiEnterInterruptTrap(TrapFrame);
/* Start the interrupt */
if (!HalBeginSystemInterrupt(CLOCK_LEVEL, HalpClockVector, &Irql))
{
/* Spurious, just end the interrupt */
KiEoiHelper(TrapFrame);
}
/* Read register C, so that the next interrupt can happen */
HalpReadCmos(RTC_REGISTER_C);;
/* Save increment */
LastIncrement = HalpCurrentTimeIncrement;
/* Check if someone changed the time rate */
if (HalpClockSetMSRate)
{
/* Set new clock rate */
RtcSetClockRate(HalpCurrentRate);
/* We're done */
HalpClockSetMSRate = FALSE;
}
/* Update the system time -- on x86 the kernel will exit this trap */
KeUpdateSystemTime(TrapFrame, LastIncrement, Irql);
}
KeUpdateSystemTime函数做两个操作,第一部分查看定时器时间是否已经到期,若时间到期则调用软中断进行定时器提交;第二部分更新系统的运行时间,更具运行时间的更新进行线程切换。在KeUpdateSystemTime函数里面会调用KeUpdateR