当前位置 主页 > 服务器问题 > Linux/apache问题 >

    Linux之时钟中断详解(2)

    栏目:Linux/apache问题 时间:2019-10-11 10:13

    CLOCK_TICK_RATE是整个8253的输入脉冲,如图5.3中所示为1.193180MHz,是近似为1MHz的方波信号,8253内部的三个计数器都对这个时钟进行计数,进而产生不同的输出信号,用于不同的用途。

    HZ表示计数器0的频率,也就是时钟中断或系统时钟的频率,在/include/asm/param.h中定义如下:

    #define HZ 100

    2.与时钟中断相关的函数

    下面我们看时钟中断触发的服务程序,该程序代码比较复杂,分布在不同的源文件中,主要包括如下函数:

    时钟中断程序:timer_interrupt( );

    中断服务通用例程do_timer_interrupt();

    时钟函数:do_timer( );

    中断安装程序:setup_irq( );

    中断返回函数:ret_from_intr( );

    (1) timer_interrupt( )

    这个函数大约每10ms被调用一次,实际上, timer_interrupt( )函数是一个封装例程,它真正做的事情并不多,但是,作为一个中断程序,它必须在关中断的情况下执行。如果只考虑单处理机的情况,该函数主要语句就是调用do_timer_interrupt()函数。

    (2) do_timer_interrupt()

    do_timer_interrupt()函数有两个主要任务,一个是调用do_timer( ),另一个是维持实时时钟(RTC,每隔一定时间段要回写),其实现代码在/arch/i386/kernel/time.c中, 为了突出主题,笔者对以下函数作了改写,以便于读者理解:

    static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) 
    { 
     do_timer(regs); /* 调用时钟函数,将时钟函数等同于时钟中断未尝不可*/ 
     if(xtime.tv_sec > last_rtc_update + 660) 
     update_RTC(); 
     /*每隔11分钟就更新RTC中的时间信息,以使OS时钟和RTC时钟保持同步,11分钟即660秒,xtime.tv_sec的单位是秒,last_rtc_update记录的是上次RTC更新时的值 */             
    } 

    其中,xtime是前面所提到的timeval类型,这是一个全局变量。

    (3) 时钟函数do_timer() (在/kernel/sched.c中)

    void do_timer(struct pt_regs * regs) 
    { 
     (*(unsigned long *)&jiffies)++; /*更新系统时间,这种写法保证对jiffies 
     
    操作的原子性*/ 
     update_process_times(); 
     ++lost_ticks; 
     if( ! user_mode ( regs ) ) 
      ++lost_ticks_system; 
      mark_bh(TIMER_BH);    
     if (tq_timer)      
      mark_bh(TQUEUE_BH); 
    } 

    其中,update_process_times()函数与进程调度有关,从函数的名子可以看出,它处理的是与当前进程与时间有关的变量,例如,要更新当前进程的时间片计数器counter,如果counter<=0,则要调用调度程序,要处理进程的所有定时器:实时、虚拟、概况,另外还要做一些统计工作。

    与时间有关的事情很多,不能全都让这个函数去完成,这是因为这个函数是在关中断的情况下执行,必须处理完最重要的时间信息后退出,以处理其他事情。那么,与时间相关的其他信息谁去处理,何时处理?这就是由第三章讨论的后半部分去去处理。 上面timer_interrupt()(包括它所调用的函数)所做的事情就是上半部分。

    在该函数中还有两个变量lost_ticks和lost_ticks_system,这是用来记录timer_bh()执行前时钟中断发生的次数。因为时钟中断发生的频率很高(每10ms一次),所以在timer_bh()执行之前,可能已经有时钟中断发生了,而timer_bh()要提供定时、记费等重要操作,所以为了保证时间计量的准确性,使用了这两个变量。lost_ticks用来记录timer_bh()执行前时钟中断发生的次数,如果时钟中断发生时当前进程运行于内核态,则lost_ticks_system用来记录timer_bh()执行前在内核态发生时钟中断的次数,这样可以对当前进程精确记费。