时间子系统11_clockevent周期触发模式

  1. //  设置clockevent周期处理函数
  2. //  函数参数:
  3. //      broadcast,指示此设备是否为全局广播设备
  4. //  调用路径:tick_setup_periodic->tick_set_periodic_handler
  5. 1.1 void tick_set_periodic_handler(struct clock_event_device *dev, int broadcast)
  6. {
  7.     if (!broadcast)
  8.         dev->event_handler = tick_handle_periodic;
  9.     else
  10.         dev->event_handler = tick_handle_periodic_broadcast;
  11. }
  12. //  clockevent周期处理函数(非广播设备)
  13. //  函数任务:
  14. //      1.执行周期任务
  15. //      2.如果设备为单触发模式
  16. //          2.1 重编程下一次事件到期时间
  17. 2.1 void tick_handle_periodic(struct clock_event_device *dev)
  18. {
  19.     int cpu = smp_processor_id();
  20.     ktime_t next;
  21.     //执行do_timer更新全局事件,更新进程时间
  22.     tick_periodic(cpu);
  23.     //周期模式不需要手动设置下次到期时间,直接退出
  24.     if (dev->mode != CLOCK_EVT_MODE_ONESHOT)
  25.         return;
  26.     //计算下次到期时间
  27.     next = ktime_add(dev->next_event, tick_period);
  28.     for (;;) {
  29.         //重编程设备事件到期
  30.         if (!clockevents_program_event(dev, next, ktime_get()))
  31.             return;
  32.         //重新编程设备失败,说明已经经过一个tick周期,此时执行tick周期任务
  33.         if (timekeeping_valid_for_hres())
  34.             tick_periodic(cpu);
  35.         //更新下次到期时间
  36.         next = ktime_add(next, tick_period);
  37.     }
  38. }
  39. //  周期处理函数
  40. //  函数任务:
  41. //      1.如果本cpu负责更新全局时间
  42. //          1.1 执行do_timer
  43. //      2.更新进程运行时间
  44. //          2.1 通知调度器更新其虚拟时钟
  45. //          2.2 更新进程cpu上执行时间
  46. //  调用路径:tick_handle_periodic->tick_periodic
  47. 2.2 static void tick_periodic(int cpu)
  48. {
  49.     //本cpu负责更新全局时间
  50.     if (tick_do_timer_cpu == cpu) {
  51.         write_seqlock(&xtime_lock);
  52.         //计算下个周期
  53.         tick_next_period = ktime_add(tick_next_period, tick_period);
  54.         //执行do_timer
  55.         do_timer(1);
  56.         write_sequnlock(&xtime_lock);
  57.     }
  58.     //更新进程时间
  59.     update_process_times(user_mode(get_irq_regs()));
  60. }
  61. //  更新全局时间
  62. //  函数任务:
  63. //      1.更新jiffies
  64. //      2.更新墙上时间
  65. //      3.cpu间负载均衡
  66. //  调用路径:tick_periodic->do_timer
  67. 2.3 void do_timer(unsigned long ticks)
  68. {
  69.     jiffies_64 += ticks;
  70.     update_wall_time();
  71.     calc_global_load();
  72. }
  73. //  更新当前进程时间
  74. //  函数任务:
  75. //      1.统计进程在cpu上运行的时间
  76. //      2.运行低分辨率定时器
  77. //      3.通知调度器更新器虚拟时钟
  78. //  调用路径:tick_periodic->update_process_times
  79. 2.4 void update_process_times(int user_tick)
  80. {
  81.     struct task_struct *p = current;
  82.     int cpu = smp_processor_id();
  83.     //统计进程在cpu上运行的时间
  84.     account_process_tick(p, user_tick);
  85.     //运行低分辨率定时器
  86.     run_local_timers();
  87.     //以HZ频率,通知调度器更新其虚拟时钟
  88.     scheduler_tick();
  89. }
  90. //  clockevent周期处理函数(广播设备)
  91. //  函数任务:
  92. //      1.执行本cpu的事件处理函数
  93. //      2.通过ipi通知代理的cpu,执行时间处理函数
  94. //      3.重新编程下次事件的到期时间
  95. 3.1 static void tick_handle_periodic_broadcast(struct clock_event_device *dev)
  96. {
  97.     ktime_t next;
  98.     //执行事件处理函数
  99.     tick_do_periodic_broadcast();
  100.     //重编程下次事件的到期时间
  101.     if (dev->mode == CLOCK_EVT_MODE_PERIODIC)
  102.         return;
  103.     for (next = dev->next_event; 😉 {
  104.         next = ktime_add(next, tick_period);
  105.         if (!clockevents_program_event(dev, next, ktime_get()))
  106.             return;
  107.         tick_do_periodic_broadcast();
  108.     }
  109. }
  110. //  执行事件处理函数
  111. //  函数任务:
  112. //      1.通过tick_broadcast_mask掩码获取代理的cpu
  113. //      2.执行事件处理函数
  114. //  调用路径:tick_handle_periodic_broadcast->tick_do_periodic_broadcast
  115. 3.2 static void tick_do_periodic_broadcast(void)
  116. {
  117.     raw_spin_lock(&tick_broadcast_lock);
  118.     //通过tick_broadcast_mask掩码获取代理的cpu
  119.     cpumask_and(to_cpumask(tmpmask),
  120.             cpu_online_mask, tick_get_broadcast_mask());
  121.     //对代理的cpu执行事件处理函数
  122.     tick_do_broadcast(to_cpumask(tmpmask));
  123.     raw_spin_unlock(&tick_broadcast_lock);
  124. }
  125. //  执行事件处理函数
  126. //  函数任务:
  127. //      1.执行本cpu的事件处理函数
  128. //      2.通过ipi通知代理的cpu,执行事件处理函数
  129. //  调用路径:tick_handle_periodic_broadcast->…->tick_do_broadcast
  130. 3.3 static void tick_do_broadcast(struct cpumask *mask)
  131. {
  132.     int cpu = smp_processor_id();
  133.     struct tick_device *td;
  134.     //检查当前cpu是否在掩码
  135.     if (cpumask_test_cpu(cpu, mask)) {
  136.         //从掩码中清除本cpu
  137.         cpumask_clear_cpu(cpu, mask);
  138.         td = &per_cpu(tick_cpu_device, cpu);
  139.         //执行事件处理函数
  140.         td->evtdev->event_handler(td->evtdev);
  141.     }
  142.     //检查是否有其他cpu需要被代理
  143.     if (!cpumask_empty(mask)) {
  144.         //通过ipi通知其他cpu执行时钟事件处理函数
  145.         td = &per_cpu(tick_cpu_device, cpumask_first(mask));
  146.         td->evtdev->broadcast(mask);
  147.     }
  148. }
  149. //  x86下lapic,clockevent->broadcast函数
  150. //  函数任务:
  151. //      通过ipi通知目标cpu执行事件处理函数
  152. 3.4 static void lapic_timer_broadcast(const struct cpumask *mask)
  153. {
  154. #ifdef CONFIG_SMP
  155.     //所有需要通知的cpu均在mask掩码中
  156.     apic->send_IPI_mask(mask, LOCAL_TIMER_VECTOR);
  157. #endif
  158. }

标签