我是靠谱客的博主 妩媚大树,这篇文章主要介绍时间子系统13_clockevent周期触发模式,现在分享给大家,希望可以做个参考。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// 设置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周期触发模式内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(93)

评论列表共有 0 条评论

立即
投稿
返回
顶部