- 论坛徽章:
- 0
|
本帖最后由 l4rmbr 于 2015-08-27 09:09 编辑
super皮波 发表于 2014-11-17 17:44 ![]()
void hrtimer_run_pending(void)
{
if (hrtimer_hres_active())
就在hrtimer_switch_to_hres里切换的。
高精度(hres) 和 nohz 都依赖于 ONESHOT 模式。 以前的 tick 模式,时钟是周期性触发的,也就是到点就来一个中断。
但在 高精度(hres) 模式下,这不可行。因为高精度(hres) 是 ns 级别的高精度,如此频繁的周期中断,系统不用干别的事了。
nohz 情况下,周期性的 tick 当然也不可行。nohz 本来就是动态tick, 需要的时候来,不需要的时候干脆关掉。这就是 ONESHOT mode 的作用。
ONESHOT, 顾名思义,就是一次中断来了后,要配置下一次什么时候来,也可以配置暂时关闭。
看内核配置也可以看到出来:
config NO_HZ_COMMON
bool
select TICK_ONESHOT
config HIGH_RES_TIMERS
bool "High Resolution Timer Support"
select TICK_ONESHOT
help
| This option enables high resolution timer support. If your
| hardware is not capable then this option only increases
| the size of the kernel image.
这两者者要 选择 TICK_ONESHOT。
系统启动时只在 低精度 和 非 nohz 模式下, 切换到这两种模式的代码是在时钟中断上下文调用的:
时钟中断来了 -》 tick_handle_periodic -》 tick_periodic -》update_process_times -》 run_local_timers -》 hrtimer_run_pending:
if (tick_check_oneshot_change(!hrtimer_is_hres_enabled())) {
hrtimer_switch_to_hres();
return;
}
tick_check_oneshot_change 是进入 高精度(hres) 和 nohz 的总入口:
int tick_check_oneshot_change(int allow_nohz)
{
struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched);
if (!test_and_clear_bit(0, &ts->check_clocks))
return 0;
if (ts->nohz_mode != NOHZ_MODE_INACTIVE)
return 0;
if (!timekeeping_valid_for_hres() || !tick_is_oneshot_available())
return 0;
if (!allow_nohz)
return 1;
tick_nohz_switch_to_nohz();
return 0;
}
如果 高精度(hres) 还不可用 , 那么,检查 nohz 是否可以激活,可以的话,我们先进入 nohz.
tick_nohz_switch_to_nohz 被调用,系统现在进入 低精度,nohz 模式。
这一函数的主要功能是
1) 把 时钟中断 处理 函数 改为: tick_nohz_handler . 注意看前文 ,一开始的时钟中断函数是 tick_handle_periodic。
2) 用hrtimer 框架, 设定下一次触发的时间,也就 是下一个 tick (注意,你看到用了hrtimer_* 函数,但不代表 高精度(hres) 激活了,
hrtimer 框架 和 高精度(hres) 是两回事,hres是建立 在 hrtimer 框架上的,低精度也可以使用 hrtimer 框架, 这个框架提供的无非
是配置动态时钟的功能,看 kernel/time/Makefile 也可以看出来,hrtimer.c 是无条件编译的,而 高精度(hres) 可不可用要看 CONFIG_HIGH_RES_TIMERS)
OK, 现在是低精度,nohz 模式了, 时钟中断处理函数是 tick_nohz_handler.
下一次时钟中断来了,时钟中断处理过程是:
tick_nohz_handler -》 tick_sched_handle -》 update_process_times -》 run_local_timers -》 hrtimer_run_pending:
看,其实做的事差不多。
现在我们又来到 hrtimer_run_pending 了, 记住,现在已经是 低精度,nohz 模式 了, 我们要检查 高精度(hres) 是否可用了,
是的话,我们要进入 高精度 (hres) 模式了。 假设可用了,.
if (tick_check_oneshot_change(!hrtimer_is_hres_enabled())) {
hrtimer_switch_to_hres();
return;
}
hrtimer_switch_to_hres 试图把系统切换到 高精度 (hres) 模式.
hrtimer_switch_to_hres -> tick_init_highres -> tick_switch_to_oneshot(hrtimer_interrupt)
注意,切换的核心动作是要把时钟中断的处理函数变为 hrtimer_interrupt:
/*
* High resolution timer interrupt
* Called with interrupts disabled
*/
void hrtimer_interrupt(struct clock_event_device *dev)
{
...
}
这个函数就是 高精度 (hres) 模式 下的时钟中断处理函数 ,它负责跑已经到点的定时器,
根据系统是否在 nohz 模式下, 决定配置下次时钟中断的时间,或者关掉时钟中断,等。
上面整个流程也可以有别的途径,比如,先进入 高精度 (hres) 模式, 再进入 nohz;或
只进入 高精度 (hres) 模式,不进入 nohz (原因是用户没把 nohz 功能编译进来 )。具体流程
与上文无多大差别,还是在时钟中断中去判断,然后进入。不再赘述。 |
|