閱讀441 返回首頁    go 技術社區[雲棲]


時間子係統13_clockevent周期觸發模式

//	設置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
}

最後更新:2017-04-03 14:54:38

  上一篇:go Android使用ListView
  下一篇:go 基於xmpp聊天室實現,國外牛人作品