微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > Linux 时钟管理

Linux 时钟管理

时间:06-13 来源:IBM 点击:

hrtimer_bases 是实现 hrtimer 的核心数据结构,通过 hrtimer_bases,hrtimer 可以管理挂在每一个 CPU 上的所有 timer。每个 CPU 上的 timer list 不再使用 timer wheel 中多级链表的实现方式,而是采用了红黑树(Red-Black Tree)来进行管理。hrtimer_bases 的定义如清单 4 所示:

清单 4. hrtimer_bases 的定义

DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) = { .clock_base = { { .index = CLOCK_REALTIME, .get_time = &ktime_get_real, .resolution = KTIME_LOW_RES, }, { .index = CLOCK_MONOTONIC, .get_time = &ktime_get, .resolution = KTIME_LOW_RES, }, } };

图 4 展示了 hrtimer 如何通过 hrtimer_bases 来管理 timer。

图 3. hrtimer 的时钟管理

每个 hrtimer_bases 都包含两个 clock_base,一个是 CLOCK_REALTIME 类型的,另一个是 CLOCK_MONOTONIC 类型的。hrtimer 可以选择其中之一来设置 timer 的 expire time, 可以是实际的时间 , 也可以是相对系统运行的时间。

在 hrtimer_run_queues 的处理中,首先要通过 hrtimer_bases 找到正在执行当前中断的 CPU 相关联的 clock_base,然后逐个检查每个 clock_base 上挂的 timer 是否超时。由于 timer 在添加到 clock_base 上时使用了红黑树,最早超时的 timer 被放到树的最左侧,因此寻找超时 timer 的过程非常迅速,找到的所有超时 timer 会被逐一处理。超时的 timer 根据其类型分为 softIRQ / per-CPU / unlocked 几种。如果一个 timer 是 softIRQ 类型的,这个超时的 timer 需要被转移到 hrtimer_bases 的 cb_pending 的 list 上,待 IRQ0 的软中断被激活后,通过 run_hrtimer_pending 执行,另外两类则必须在 hardIRQ 中通过 __run_hrtimer 直接执行。不过在较新的 kernel(> 2.6.29)中,cb_pending 被取消,这样所有的超时 timers 都必须在 hardIRQ 的 context 中执行。这样修改的目的,一是为了简化代码逻辑,二是为了减少 2 次 context 的切换:一次从 hardIRQ 到 softIRQ,另一次从 softIRQ 到被超时 timer 唤醒的进程。

在 update_process_times 中,除了处理处于低精度模式的 hrtimer 外,还要唤醒 IRQ0 的 softIRQ(TIMER_SOFTIRQ(run_timer_softirq))以便执行 timer wheel 的代码。由于 hrtimer 子系统的加入,在 IRQ0 的 softIRQ 中,还需要通过 hrtimer_run_pending 检查是否可以将 hrtimer 切换到高精度模式,如清单 5 所示:

清单 5. hrtimer 进行精度切换的处理函数

void hrtimer_run_pending(void) { if (hrtimer_hres_active()) return; /* * This _is_ ugly: We have to check in the softirq context, * whether we can switch to highres and / or nohz mode. The * clocksource switch happens in the timer interrupt with * xtime_lock held. Notification from there only sets the * check bit in the tick_oneshot code, otherwise we might * deadlock vs. xtime_lock. */ if (tick_check_oneshot_change(!hrtimer_is_hres_enabled())) hrtimer_switch_to_hres(); }

正如这段代码的作者注释中所提到的,每一次触发 IRQ0 的 softIRQ 都需要检查一次是否可以将 hrtimer 切换到高精度,显然是十分低效的,希望将来有更好的方法不用每次都进行检查。

如果可以将 hrtimer 切换到高精度模式,则调用 hrtimer_switch_to_hres 函数进行切换。如清单 6 所示:

清单 6. hrtimer 切换到高精度模式的核心函数

/* * Switch to high resolution mode */ static int hrtimer_switch_to_hres(void) { int cpu = smp_processor_id(); struct hrtimer_cpu_base *base = &per_cpu(hrtimer_bases, cpu); unsigned long flags; if (base->hres_active) return 1; local_irq_save(flags); if (tick_init_highres()) { local_irq_restore(flags); printk(KERN_WARNING "Could not switch to high resolution " "mode on CPU %d\n", cpu); return 0; } base->hres_active = 1; base->clock_base[CLOCK_REALTIME].resolution = KTIME_HIGH_RES; base->clock_base[CLOCK_MONOTONIC].resolution = KTIME_HIGH_RES; tick_setup_sched_timer(); /* "Retrigger" the interrupt to get things going */ retrigger_next_event(NULL); local_irq_restore(flags); return 1; }

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top