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

Linux 时钟管理

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

,因此 tick 中断不会是周期产生的。

Dynamic tick 的开始和停止

当 CPU 进入空闲时是最好的时机。此时可以启动 dynamic tick 机制,停止 tick;反之在 CPU 从空闲中恢复到工作状态时,则可以停止 dynamic tick。见清单 11 所示:

清单 11. CPU 在 idle 时 dynamic tick 的启动 / 停止设置

void cpu_idle(void) { . . . . while (1) { tick_nohz_stop_sched_tick(1); while (!need_resched()) { . . . . } tick_nohz_restart_sched_tick(); } . . . . }

timer 子系统的初始化过程

在分别了解了内核时钟子系统各个模块后,现在可以系统的介绍内核时钟子系统的初始化过程。系统刚上电时,需要注册 IRQ0 时钟中断,完成时钟源设备,时钟事件设备,tick device 等初始化操作并选择合适的工作模式。由于刚启动时没有特别重要的任务要做,因此默认是进入低精度 + 周期 tick 的工作模式,之后会根据硬件的配置(如硬件上是否支持 HPET 等高精度 timer)和软件的配置(如是否通过命令行参数或者内核配置使能了高精度 timer 等特性)进行切换。在一个支持 hrtimer 高精度模式并使能了 dynamic tick 的系统中,第一次发生 IRQ0 的软中断时 hrtimer 就会进行从低精度到高精度的切换,然后再进一步切换到 NOHZ 模式。IRQ0 为系统的时钟中断,使用全局的时钟事件设备(global_clock_event)来处理的,其定义如下:

static struct irqaction irq0 = { .handler = timer_interrupt, .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER, .name = "timer" };

它的中断处理函数 timer_interrupt 的简化实现如清单 12 所示:

清单 12. IRQ0 中断处理函数的简化实现

static irqreturn_t timer_interrupt(int irq, void *dev_id) { . . . . global_clock_event->event_handler(global_clock_event); . . . . return IRQ_HANDLED; }

在 global_clock_event->event_handler 的处理中,除了更新 local CPU 上运行进程时间的统计,profile 等工作,更重要的是要完成更新 jiffies 等全局操作。这个全局的时钟事件设备的 event_handler 根据使用环境的不同,在低精度模式下可能是 tick_handle_periodic / tick_handle_periodic_broadcast,在高精度模式下是 hrtimer_interrupt。目前只有 HPET 或者 PIT 可以作为 global_clock_event 使用。其初始化流程清单 13 所示:

清单 13. timer 子系统的初始化流程

void __init time_init(void) { late_time_init = x86_late_time_init; } static __init void x86_late_time_init(void) { x86_init.timers.timer_init(); tsc_init(); } /* x86_init.timers.timer_init 是指向 hpet_time_init 的回调指针 */ void __init hpet_time_init(void) { if (!hpet_enable()) setup_pit_timer(); setup_default_timer_irq(); }

由清单 13 可以看到,系统优先使用 HPET 作为 global_clock_event,只有在 HPET 没有使能时,PIT 才有机会成为 global_clock_event。在使能 HPET 的过程中,HPET 会同时被注册为时钟源设备和时钟事件设备。

hpet_enable hpet_clocksource_register hpet_legacy_clockevent_register clockevents_register_device(&hpet_clockevent);

clockevent_register_device 会触发 CLOCK_EVT_NOTIFY_ADD 事件,即创建对应的 tick device。然后在 tick_notify 这个事件处理函数中会添加新的 tick device。

clockevent_register_device trigger event CLOCK_EVT_NOTIFY_ADD tick_notify receives event CLOCK_EVT_NOTIFY_ADD tick_check_new_device tick_setup_device

在 tick device 的设置过程中,会根据新加入的时钟事件设备是否使用 broadcast 来分别设置 event_handler。对于 tick device 的处理函数,可见图 5 所示:

表 2. tick device 在不同模式下的处理函数

low resolution

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

网站地图

Top