Chinaunix首页 | 论坛 | 博客
  • 博客访问: 792970
  • 博文数量: 118
  • 博客积分: 2067
  • 博客等级: 大尉
  • 技术积分: 1751
  • 用 户 组: 普通用户
  • 注册时间: 2009-07-17 14:27
文章存档

2016年(1)

2013年(1)

2012年(3)

2011年(26)

2010年(47)

2009年(40)

分类: LINUX

2011-04-25 10:07:14

------------------------------------------
硬件: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:
  1. 62 DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
  2.   63 {
  3.   64
  4.   65 .clock_base =
  5.   66 {
  6.   67   {
  7.   68    .index = CLOCK_REALTIME,
  8.   69    .get_time = &ktime_get_real,
  9.   70    .resolution = KTIME_LOW_RES,
  10.   71    },
  11.   72    {
  12.   73   .index = CLOCK_MONOTONIC,
  13.   74   .get_time = &ktime_get,
  14.   75   .resolution = KTIME_LOW_RES,
  15.   76   },
  16.   77 }
  17.   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中,为:
  1. 1330 /* Reprogramming necessary ? */
  2. 1331 if (expires_next.tv64 == KTIME_MAX ||
  3. 1332 !tick_program_event(expires_next, 0)) {
  4. 1333 cpu_base->hang_detected = 0;
  5. 1334 return;
  6. 1335 }
  7. 1336
  8. 1337 /*
  9. 1338 * The next timer was already expired due to:
  10. 1339 * - tracing
  11. 1340 * - long lasting callbacks
  12. 1341 * - being scheduled away when running in a VM
  13. 1342 *
  14. 1343 * We need to prevent that we loop forever in the hrtimer
  15. 1344 * interrupt routine. We give it 3 attempts to avoid
  16. 1345 * overreacting on some spurious event.
  17. 1346 */
  18. 1347 now = ktime_get();
  19. 1348 cpu_base->nr_retries++;
  20. 1349 if (++retries < 3)
  21. 1350 goto retry;



阅读(2791) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~