概述
// 高分辨率模式下的周期事件仿真
// 通过hrtimer仿真周期时钟,由hrtimer_interrupt作为时钟事件处理函数
// 函数任务:
// 1.更新jiffies
// 2.在irq上下文
// 2.1 如果当前处于idle状态
// 2.1.1 喂狗softlockup_watchdog,防止误发生softlockup
// 2.1.2 更新idle状态经历的jiffies
// 2.2 更新进程时间
// 3.调度hrtimer下一个周期继续运行
1.1 static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer)
{
struct tick_sched *ts =
container_of(timer, struct tick_sched, sched_timer);
struct pt_regs *regs = get_irq_regs();
ktime_t now = ktime_get();
int cpu = smp_processor_id();
//高分辨率模式下,如果支持动态时钟,则需要检查是否本cpu负责更新全局时间
#ifdef CONFIG_NO_HZ
//负责更新jiffies
if (unlikely(tick_do_timer_cpu == TICK_DO_TIMER_NONE))
tick_do_timer_cpu = cpu;
#endif
if (tick_do_timer_cpu == cpu)
tick_do_update_jiffies64(now);
//在irq上下文
if (regs) {
//当前处于idle状态
if (ts->tick_stopped)
{
//喂狗,防止误发生softlockup
touch_softlockup_watchdog();
//更新idle状态的jiffies
ts->idle_jiffies++;
}
//更新进程时间
update_process_times(user_mode(regs));
}
//调度hrtimer下一个周期继续运行
hrtimer_forward(timer, now, tick_period);
return HRTIMER_RESTART;
}
// 关闭时钟
// 函数任务:
// 1.检查下一个定时器轮事件是否在一个周期之后
// 1.1 如果是这样,重新编程clockevent设备,直到未来合适的时间才恢复。
// 2.在tick_sched中更新统计信息
// 注:在idle进程中停用时钟
2.1 void tick_nohz_stop_sched_tick(int inidle);
..
// 恢复时钟
// 函数任务:
// 1.更新jiffies
// 2.统计tick_sched中idle时间
// 3.设置tick_sched->tick_stopped=0,因此时钟现在再次激活
// 4.重编程clockevent设备
2.2 void tick_nohz_restart_sched_tick(void);
..
// 动态时钟数据结构
3.1
struct tick_sched {
struct hrtimer sched_timer; //用于实现动态时钟的定时器
unsigned long check_clocks;
enum tick_nohz_mode nohz_mode; //当前动态时钟所处的模式
ktime_t idle_tick; //存储在禁用周期时钟之前,上一个时钟信号的到期时间
int inidle; //处于idle进程中
int tick_stopped; //1,即当前没有基于周期时钟信号的工作要做,否则为0
unsigned long idle_jiffies; //存储周期时钟禁用时的jiffies
unsigned long idle_calls; //内核试图停用周期时钟的次数
unsigned long idle_sleeps; //存储了周期时钟上一次禁用的时间
int idle_active; //激活了idle状态
ktime_t idle_entrytime; //idle 被调用时的时间
ktime_t idle_waketime; //idle 被打断的时间
ktime_t idle_exittime; //离开idle状态的时间
ktime_t idle_sleeptime; //累计时钟停用的总时间
ktime_t idle_lastupdate;
ktime_t sleep_length; //存储周期时钟将禁用的长度,即从时钟禁用起,到预计将发生下一个时钟信号为止
unsigned long last_jiffies; //
unsigned long next_jiffies; //存储了下一个定时器到期的jiffies值
ktime_t idle_expires; //下一个将到期的经典定时器的到期时间
int do_timer_last; //记录此cpu在停用时钟之前是否为执行do_timer的cpu
}
// 低分辨率模式下的动态时钟事件处理函数
// 在低分辨率模式下开启动态时钟时,关闭周期时钟,由该函数处理时钟事件。
4.1 static void tick_nohz_handler(struct clock_event_device *dev)
{
struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
struct pt_regs *regs = get_irq_regs();
int cpu = smp_processor_id();
ktime_t now = ktime_get();
dev->next_event.tv64 = KTIME_MAX;
//由本cpu负责更新全局时间
if (unlikely(tick_do_timer_cpu == TICK_DO_TIMER_NONE))
tick_do_timer_cpu = cpu;
//更新全局时间
if (tick_do_timer_cpu == cpu)
tick_do_update_jiffies64(now);
//idle状态停用了周期时钟,喂狗,防止误发生softlockup
if (ts->tick_stopped) {
touch_softlockup_watchdog();
//更新idle状态持续的jiffies
ts->idle_jiffies++;
}
//更新本cpu的时间
update_process_times(user_mode(regs));
profile_tick(CPU_PROFILING);
//重编程下一个时钟事件到期时间
while (tick_nohz_reprogram(ts, now)) {
now = ktime_get();
tick_do_update_jiffies64(now);
}
}
最后
以上就是懦弱鸡为你收集整理的时间子系统8_动态时钟(NO_HZ)的全部内容,希望文章能够帮你解决时间子系统8_动态时钟(NO_HZ)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复