2.4 硬件时钟处理过程

由2.3.3可知硬件时钟中断的处理函数保存在静态变量 irq0 中,其定义如清单2-4

单2-4 变量irq0定义

static struct irqaction irq0 = {
.handler = timer_event_interrupt,
.flags  = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING,
.mask  = CPU_MASK_NONE,
.name  = "timer"
};

由定义可知:函数 timer_event_interrupt 为时钟中断处理函数,其定义如清单2-5

清单2-5 timer_event_interrupt 函数
static irqreturn_t timer_event_interrupt(int irq, void *dev_id)
{
add_pda(irq0_irqs, 1);
global_clock_event->event_handler(global_clock_event);
return IRQ_HANDLED;
}

为了说明这个问题,不妨假设系统中使用的是 hpet 时钟。由2.3.3节可知 global_clock_event 指向 hpet 时钟事件设备 hpet_clockevent )。查看 hpet_enable 函数的代码并没有发现有对 event_handler 成员的赋值。所以继续查看时钟事件设备加入事件的处理函数 tick_notify ,该函数记录了当时钟事件设备发生变化例如,新时钟事件设备的加入)时,执行那些操作参见2.3.1节),代码如清单2-6

清单2-6 tick_notify 函数

static int tick_notify(struct notifier_block *nb, unsigned long reason, void *dev)
{
switch (reason) {
case CLOCK_EVT_NOTIFY_ADD:
return tick_check_new_device(dev);
……
return NOTIFY_OK;
}

由代码可知:对于新加入时钟事件设备这个事件,将会调用函数 tick_check_new_device 。顺着该函数的调用序列向下查找。tick_set_periodic_handler 函数将时钟事件设备的 event_handler 成员赋值为 tick_handle_periodic 函数的地址。由此可知,函数 tick_handle_periodic 为硬件时钟中断发生时,真正的运行函数。

函数 tick_handle_periodic 的处理过程分成了以下两个部分:

  1. 全局处理:整个系统中的信息处理
  2. 局部处理:局部于本地 CPU 的处理

总结一下,一次时钟中断发生后, OS 主要执行的操作 tick_handle_periodic ):

  • 全局处理仅在一个 CPU 上运行):
  1. 更新 jiffies_64
  2. 更新 xtimer 和当前时钟源信息等
  3. 根据 tick 计算 avenrun 负载
  • 局部处理每个 CPU 都要运行):
    1. 根据当前在用户态还是核心态,统计当前进程的时间:用户态时间还是核心态时间
    2. 唤醒 TIMER_SOFTIRQ 软中断
    3. 唤醒 RCU 软中断
    4. 调用 scheduler_tick 更新进程时间片等等操作,更多内容参见参考文献)
    5. profile_tick 函数调用

以上就介绍完了硬件时钟的处理过程,下面来看软件时钟。


相关内容