------------------------------------------
硬件:PowerPC P1020MBG-PC,linux版本:2.6.35
------------------------------------------
几个时间概念及变量定义:(in kernel 3.11 these variables are keeped in "struct timekeeper timekeeper;")
A:struct timespec wall_to_monotonic __attribute__ ((aligned (16)));
由墙上时间到单调时间转换时使用的中间变量。
B: struct timespec xtime __attribute__ ((aligned (16)));
表示系统的当前墙上时间与1970年1月1日0时0分0秒的偏移。即如果当前date命令显示时间为1970年1月1日0时0分0秒,则此变量结构体的的sec和nsec元素值均为0.
C:
-
62 DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
-
63 {
-
64
-
65 .clock_base =
-
66 {
-
67 {
-
68 .index = CLOCK_REALTIME,
-
69 .get_time = &ktime_get_real,
-
70 .resolution = KTIME_LOW_RES,
-
71 },
-
72 {
-
73 .index = CLOCK_MONOTONIC,
-
74 .get_time = &ktime_get,
-
75 .resolution = KTIME_LOW_RES,
-
76 },
-
77 }
-
78 };
表示高精度使用的两个时间单位,一个是真实时间,用ktime_get_real函数获取,得到的是纳秒数,与xtime变量换算成纳秒值后相同(由于精度和更新频率的原因会有10微秒级误差)。时间值为自70年以来的偏移纳秒数,公式表示为:
kt = ktime_get_real();
kt.tv.sec = xtime.sec;
kt.tv.nsec = xtime.nsec;
另一个是相对时间,即系统启动后经过的纳秒数,用ktime_get获取,与其它变量关系为:
ktime_get().tv.sec =
xtime.sec + wall_to_monotonic.tv_sec;
ktime_get().tv.nsec = xtime.nsec + wall_to_monotonic.tv_nsec
1. 当使用高精度模式时,周期性的TICK中断是由高精度的定时器模拟的,定时的频率为HZ。实现的代码在向高精度的切换过程中,代码流为:
hrtimer_switch_to_hres
tick_setup_sched_timer
hrtimer_init(&ts->sched_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
ts->sched_timer.function = tick_sched_timer;
TICK周期函数的执行流程为:
tick_sched_timer
update_process_times
run_local_timers
hrtimer_run_queues
raise_softirq(TIMER_SOFTIRQ);
其中:raise_softirq是为了执行低精度模式计时器的需要。
hrtimer_run_queues为了实现低精度模式下高精度定时器的需要,虽然是低精度模式,高精度定时器也被支持,只是不具有高精度模式的高分辨率性能。
2. 当没有高精度模式时钟源支持时,高精度定时器只有低精度性能,下面分析高精度定时器在高精度模式下的实现和使用。
A: 初始化的流程图为:
hrtimer_init
__hrtimer_init(timer, clock_id, mode)
此函数只是对定时器的时基赋值,即:timer->base = &cpu_base->clock_base[clock_id];
B:启动定时器的流程为:
hrtimer_start
__hrtimer_start_range_ns(timer, tim, 0, mode, 1);
hrtimer_enqueue_reprogram
hrtimer_reprogram
hrtimer_enqueue_reprogram函数不是一定被调用,在当前定时器为最早到期定期时器并且当前的CPU是定时器的CPU时会被调用,以用来重新设置下次时间中断的到期值。如果不重新设置这个值,下次时钟中断产生时,本定时器早已过期。
C:定时器的到期检测点:
如果新加入的定时器为最新到期的定时器,则要对event设备重新编程,以确保这个新定时器不会被漏处理。如果新加入的不是最近到期的,直接返回,它的event中断在hrtimer_interrupt函数中去编程设置。hrtimer_interrupt会检测到期的中断,并直接处理这些中断。然后编程下个中断时间。 __run_hrtimer(timer, &basenow);函数执行定时器函数。
这里会产生一个问题是:如果下一个定时器到期时间已经过了,怎么办?
在内核中如果遇到这种情况,hrtimer_interrupt会继续处理三个过期定时器,如果还有过期时钟,则退出留到下个定时中断再处理,以免此处理占用过多时间。相关代码在hrtimer_interrupt中,为:
-
1330 /* Reprogramming necessary ? */
-
1331 if (expires_next.tv64 == KTIME_MAX ||
-
1332 !tick_program_event(expires_next, 0)) {
-
1333 cpu_base->hang_detected = 0;
-
1334 return;
-
1335 }
-
1336
-
1337 /*
-
1338 * The next timer was already expired due to:
-
1339 * - tracing
-
1340 * - long lasting callbacks
-
1341 * - being scheduled away when running in a VM
-
1342 *
-
1343 * We need to prevent that we loop forever in the hrtimer
-
1344 * interrupt routine. We give it 3 attempts to avoid
-
1345 * overreacting on some spurious event.
-
1346 */
-
1347 now = ktime_get();
-
1348 cpu_base->nr_retries++;
-
1349 if (++retries < 3)
-
1350 goto retry;
阅读(2909) | 评论(0) | 转发(1) |