static void tick_nohz_handler(struct clock_event_device *dev) { struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); struct pt_regs *regs = get_irq_regs(); int cpu = smp_processor_id(); ktime_t now = ktime_get(); dev->next_event.tv64 = KTIME_MAX; if (unlikely(tick_do_timer_cpu == TICK_DO_TIMER_NONE)) tick_do_timer_cpu = cpu; /* Check, if the jiffies need an update */ if (tick_do_timer_cpu == cpu) tick_do_update_jiffies64(now); /* * When we are idle and the tick is stopped, we have to touch * the watchdog as we might not schedule for a really long * time. This happens on complete idle SMP systems while * waiting on the login prompt. We also increment the "start * of idle" jiffy stamp so the idle accounting adjustment we * do when we go busy again does not account too much ticks. */ if (ts->tick_stopped) { touch_softlockup_watchdog(); ts->idle_jiffies++; } update_process_times(user_mode(regs)); profile_tick(CPU_PROFILING); while (tick_nohz_reprogram(ts, now)) { now = ktime_get(); tick_do_update_jiffies64(now); } } 在这个函数中,首先模拟周期性 tick device 完成类似的工作:如果当前 CPU 负责全局 tick device 的工作,则更新 jiffies,同时完成对本地 CPU 的进程时间统计等工作。如果当前 tick device 在此之前已经处于停止状态,为了防止 tick 停止时间过长造成 watchdog 超时,从而引发 soft-lockdep 的错误,需要通过调用 touch_softlockup_watchdog 复位软件看门狗防止其溢出。正如代码中注释所描述的,这种情况有可能出现在启动完毕,完全空闲等待登录的 SMP 系统上。最后需要设置下一次 tick 的超时时间。如果 tick_nohz_reprogram 执行时间超过了一个 jiffy,会导致设置的下一次超时时间已经过期,因此需要重新设置,相应的也需要再次更新 jiffies。这里虽然设置了下一次的超时事件,但是由于系统空闲时会停止 tick,因此下一次的超时事件可能发生,也可能不发生。这也正是 dynamic tick 根本特性。 从清单 7 中可以看到,在高精度模式下 tick_sched_timer 用来模拟周期性 tick device 的功能。dynamic tick 的实现也使用了这个函数。这是因为 hrtimer 在高精度模式时必须使用 one-shot 模式的 tick device,这也同时符合 dynamic tick 的要求。虽然使用同样的函数,表面上都会触发周期性的 tick 中断,但是使用 dynamic tick 的系统在空闲时会停止 tick 工作 |