首页 > 其它语言 > 时间子系统11_clockevent周期触发模式
时间子系统11_clockevent周期触发模式
孤风一剑
11月 26, 2013
201

- // 设置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();
- }
- // 更新当前进程时间
- // 函数任务:
- // 1.统计进程在cpu上运行的时间
- // 2.运行低分辨率定时器
- // 3.通知调度器更新器虚拟时钟
- // 调用路径:tick_periodic->update_process_times
- 2.4 void update_process_times(int user_tick)
- {
- struct task_struct *p = current;
- int cpu = smp_processor_id();
- //统计进程在cpu上运行的时间
- account_process_tick(p, user_tick);
- //运行低分辨率定时器
- run_local_timers();
- //以HZ频率,通知调度器更新其虚拟时钟
- scheduler_tick();
- }
- // 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
- }