概述
// 设置clockevent周期处理函数
// 函数参数:
// broadcast,指示此设备是否为全局广播设备
// 调用路径:tick_setup_periodic->tick_set_periodic_handler
1.1 void tick_set_periodic_handler(struct clock_event_device *dev, int broadcast)
{
if (!broadcast)
dev->event_handler = tick_handle_periodic;
else
dev->event_handler = tick_handle_periodic_broadcast;
}
// clockevent周期处理函数(非广播设备)
// 函数任务:
// 1.执行周期任务
// 2.如果设备为单触发模式
// 2.1 重编程下一次事件到期时间
2.1 void tick_handle_periodic(struct clock_event_device *dev)
{
int cpu = smp_processor_id();
ktime_t next;
//执行do_timer更新全局事件,更新进程时间
tick_periodic(cpu);
//周期模式不需要手动设置下次到期时间,直接退出
if (dev->mode != CLOCK_EVT_MODE_ONESHOT)
return;
//计算下次到期时间
next = ktime_add(dev->next_event, tick_period);
for (;;) {
//重编程设备事件到期
if (!clockevents_program_event(dev, next, ktime_get()))
return;
//重新编程设备失败,说明已经经过一个tick周期,此时执行tick周期任务
if (timekeeping_valid_for_hres())
tick_periodic(cpu);
//更新下次到期时间
next = ktime_add(next, tick_period);
}
}
// 周期处理函数
// 函数任务:
// 1.如果本cpu负责更新全局时间
// 1.1 执行do_timer
// 2.更新进程运行时间
// 2.1 通知调度器更新其虚拟时钟
// 2.2 更新进程cpu上执行时间
// 调用路径:tick_handle_periodic->tick_periodic
2.2 static void tick_periodic(int cpu)
{
//本cpu负责更新全局时间
if (tick_do_timer_cpu == cpu) {
write_seqlock(&xtime_lock);
//计算下个周期
tick_next_period = ktime_add(tick_next_period, tick_period);
//执行do_timer
do_timer(1);
write_sequnlock(&xtime_lock);
}
//更新进程时间
update_process_times(user_mode(get_irq_regs()));
}
// 更新全局时间
// 函数任务:
// 1.更新jiffies
// 2.更新墙上时间
// 3.cpu间负载均衡
// 调用路径:tick_periodic->do_timer
2.3 void do_timer(unsigned long ticks)
{
jiffies_64 += ticks;
update_wall_time();
calc_global_load();
}
// clockevent周期处理函数(广播设备)
// 函数任务:
// 1.执行本cpu的事件处理函数
// 2.通过ipi通知代理的cpu,执行时间处理函数
// 3.重新编程下次事件的到期时间
3.1 static void tick_handle_periodic_broadcast(struct clock_event_device *dev)
{
ktime_t next;
//执行事件处理函数
tick_do_periodic_broadcast();
//重编程下次事件的到期时间
if (dev->mode == CLOCK_EVT_MODE_PERIODIC)
return;
for (next = dev->next_event; ;) {
next = ktime_add(next, tick_period);
if (!clockevents_program_event(dev, next, ktime_get()))
return;
tick_do_periodic_broadcast();
}
}
// 执行事件处理函数
// 函数任务:
// 1.通过tick_broadcast_mask掩码获取代理的cpu
// 2.执行事件处理函数
// 调用路径:tick_handle_periodic_broadcast->tick_do_periodic_broadcast
3.2 static void tick_do_periodic_broadcast(void)
{
raw_spin_lock(&tick_broadcast_lock);
//通过tick_broadcast_mask掩码获取代理的cpu
cpumask_and(to_cpumask(tmpmask),
cpu_online_mask, tick_get_broadcast_mask());
//对代理的cpu执行事件处理函数
tick_do_broadcast(to_cpumask(tmpmask));
raw_spin_unlock(&tick_broadcast_lock);
}
// 执行事件处理函数
// 函数任务:
// 1.执行本cpu的事件处理函数
// 2.通过ipi通知代理的cpu,执行事件处理函数
// 调用路径:tick_handle_periodic_broadcast->...->tick_do_broadcast
3.3 static void tick_do_broadcast(struct cpumask *mask)
{
int cpu = smp_processor_id();
struct tick_device *td;
//检查当前cpu是否在掩码
if (cpumask_test_cpu(cpu, mask)) {
//从掩码中清除本cpu
cpumask_clear_cpu(cpu, mask);
td = &per_cpu(tick_cpu_device, cpu);
//执行事件处理函数
td->evtdev->event_handler(td->evtdev);
}
//检查是否有其他cpu需要被代理
if (!cpumask_empty(mask)) {
//通过ipi通知其他cpu执行时钟事件处理函数
td = &per_cpu(tick_cpu_device, cpumask_first(mask));
td->evtdev->broadcast(mask);
}
}
// x86下lapic,clockevent->broadcast函数
// 函数任务:
// 通过ipi通知目标cpu执行事件处理函数
3.4 static void lapic_timer_broadcast(const struct cpumask *mask)
{
#ifdef CONFIG_SMP
//所有需要通知的cpu均在mask掩码中
apic->send_IPI_mask(mask, LOCAL_TIMER_VECTOR);
#endif
}
最后
以上就是妩媚大树为你收集整理的时间子系统13_clockevent周期触发模式的全部内容,希望文章能够帮你解决时间子系统13_clockevent周期触发模式所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复