1. 程式人生 > >把握linux核心設計思想(六):核心時鐘中斷

把握linux核心設計思想(六):核心時鐘中斷

(位於檔案kernel/time/tick-common.c)
void __init tick_init(void)
{
    clockevents_register_notifier(&tick_notifier);
}
tick_notifier定義如下:
static struct notifier_block tick_notifier = {
    .notifier_call = tick_notify,
};

static int tick_notify(struct notifier_block *nb, unsigned long reason,
                   void *dev)
{
    switch (reason) {

    ......

    case CLOCK_EVT_NOTIFY_RESUME:
        tick_resume();
        break;

    default:
        break;
    }

    return NOTIFY_OK;
}

static void tick_resume(void)
{
    struct tick_device *td = &__get_cpu_var(tick_cpu_device);
    unsigned long flags;
    int broadcast = tick_resume_broadcast();

    spin_lock_irqsave(&tick_device_lock, flags);
    clockevents_set_mode(td->evtdev, CLOCK_EVT_MODE_RESUME);

    if (!broadcast) {
        if (td->mode == TICKDEV_MODE_PERIODIC)
            tick_setup_periodic(td->evtdev, 0);
        else
            tick_resume_oneshot();
    }
    spin_unlock_irqrestore(&tick_device_lock, flags);
}

/*
 * Setup the device for a periodic tick
 */
void tick_setup_periodic(struct clock_event_device *dev, int broadcast)
{
    tick_set_periodic_handler(dev, broadcast);

    ......
}

/*
 * 根據broadcast設定週期性的處理函式(kernel/time/tick-broadcast.c),這裡就設定了始終中斷函式timer_interrupt中呼叫的時鐘處理例程
 */
void tick_set_periodic_handler(struct clock_event_device *dev, int broadcast)
{
    if (!broadcast)
        dev->event_handler = tick_handle_periodic;
    else
        dev->event_handler = tick_handle_periodic_broadcast;
}

/*
 * ,以tick_handle_periodic為例,每一個始終節拍都呼叫該處理函式,而該處理過程中,主要處理工作處於tick_periodic()函式中。
 */
void tick_handle_periodic(struct clock_event_device *dev)
{
    int cpu = smp_processor_id();
    ktime_t next;

    tick_periodic(cpu);

    if (dev->mode != CLOCK_EVT_MODE_ONESHOT)
        return;

    next = ktime_add(dev->next_event, tick_period);
    for (;;) {
        if (!clockevents_program_event(dev, next, ktime_get()))
            return;

        if (timekeeping_valid_for_hres())
            tick_periodic(cpu);
        next = ktime_add(next, tick_period);
    }
}
tick_periodic()函式主要有以下工作:
下面來看分析一下該函式:
/*
 * Periodic tick
 */
static void tick_periodic(int cpu)
{
    if (tick_do_timer_cpu == cpu) {
        write_seqlock(&xtime_lock);

        /* 記錄下一個節拍事件 */
        tick_next_period = ktime_add(tick_next_period, tick_period);

        do_timer(1);
        write_sequnlock(&xtime_lock);
    }

    update_process_times(user_mode(get_irq_regs()));//更新所耗費的各種節拍數
    profile_tick(CPU_PROFILING);
}

其中函式do_timer()(位於kernel/timer.c中)對jiffies_64做增加操作:
void do_timer(unsigned long ticks)
{
    jiffies_64 += ticks;
    update_wall_time();    //更新牆上時鐘
    calc_global_load();    //更新系統平均負載統計值
}
update_process_times更新所耗費的各種節拍數。
void update_process_times(int user_tick)
{
    struct task_struct *p = current;
    int cpu = smp_processor_id();

    /* Note: this timer irq context must be accounted for as well. */
    account_process_tick(p, user_tick);
    run_local_timers();
    rcu_check_callbacks(cpu, user_tick);
    printk_tick();
    scheduler_tick();
    run_posix_cpu_timers(p);
}
函式run_local_timers()會標記一個軟中斷去處理所有到期的定時器。
void run_local_timers(void)
{
    hrtimer_run_queues();
    raise_softirq(TIMER_SOFTIRQ);
    softlockup_tick();
}
        在時鐘中斷處理函式time_interrupt()函式呼叫體系結構無關的時鐘處理例程完成之後,返回到與體系結構的相關的中斷處理函式中。以上所有的工作每一次時鐘中斷都會執行,也就是說如果HZ=100,那麼時鐘中斷處理程式每一秒就會執行100次。