閱讀274 返回首頁    go 王者榮耀


時間子係統5_低分辨率切換高分辨率

//	切換低分辨率動態時鍾模式、或高分辨率模式
//	調用路徑:run_timer_softirq->hrtimer_run_pending
//	函數任務:
//		1.如果高分辨率定時器框架已經激活,則直接返回
//		2.切換到高分辨率模式的條件:
//			2.1 沒有開啟低分辨率動態時鍾
//			2.2 有高分辨率的clocksource
//			2.3 clockevent設備支持單觸發模式
//		3.切換到低分辨率動態時鍾的條件:
//			3.1 啟動時,沒有激活高分辨率率定時框架
//			3.2 clockevent設備支持單觸發模式
1.1 void hrtimer_run_pending(void)
{
	if (hrtimer_hres_active())
		return;

	if (tick_check_oneshot_change(!hrtimer_is_hres_enabled()))
	{
		//切換到高分辨率模式
		hrtimer_switch_to_hres();
	}
}

//	切換低分辨率模式的動態時鍾
//	函數任務:
//		1.更新tick device單觸發方式,安裝nohz事件處理函數
//		2.初始化動態時鍾數據結構
//			2.1 標識動態時鍾當前為低分辨率模式
//			2.2 動態時鍾通過單調時鍾基礎管理
//			2.3 更新動態時鍾到期時間
//		3.更新動態時鍾,tick device到期時間
2.1 static void tick_nohz_switch_to_nohz(void)
{
	struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
	ktime_t next;
	local_irq_disable();

	//更新tick device單觸發方式,安裝nohz事件處理函數
	if (tick_switch_to_oneshot(tick_nohz_handler)) {
		local_irq_enable();
		return;
	}
	//低分辨率動態時鍾標識
	ts->nohz_mode = NOHZ_MODE_LOWRES;

	//低分辨率動態時鍾依賴單調時鍾
	hrtimer_init(&ts->sched_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
	//下次到期時間
	next = tick_init_jiffy_update();

	//更新動態時鍾,tick device到期時間
	for (;;) {
		hrtimer_set_expires(&ts->sched_timer, next);
		if (!tick_program_event(next, 0))
			break;
		next = ktime_add(next, tick_period);
	}
	local_irq_enable();

}
//	低分辨率動態事件處理函數
//	函數任務:
//		1.選擇cpu負責更新jiffies
//		2.如果距離上次更新jiffies已經有1 jiffy,更新jiffies
//		3.如果動態時鍾已經停止,說明當前在idle狀態,喂狗,防止發生softlockup
//		4.更新當前進程的運行時間
//		6.更新動態時鍾的下個周期時間
//		7.重編程tick device在動態時鍾的下個周期時間到期
//	注:tick_do_timer_cpu 保存負責更新jiffies的cpu
2.2 static void tick_nohz_handler(struct clock_event_device *dev)
{
	struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
	struct pt_regs *regs = get_irq_regs();
	int cpu = smp_processor_id();
	ktime_t now = ktime_get();
	//保證tick device在最近的時間內不會到期
	dev->next_event.tv64 = KTIME_MAX;
	//選擇cpu負責更新jiffies
	if (unlikely(tick_do_timer_cpu == TICK_DO_TIMER_NONE))
		tick_do_timer_cpu = cpu;

	//更新jiffies
	if (tick_do_timer_cpu == cpu)
		tick_do_update_jiffies64(now);
	//動態時鍾停止,說明當前在idle狀態,喂狗,防止發生softlockup
	if (ts->tick_stopped) {
		touch_softlockup_watchdog();
		ts->idle_jiffies++;
	}

	//更新進程的運行時間
	update_process_times(user_mode(regs));
	//重編程clockevent設備
	while (tick_nohz_reprogram(ts, now)) {
		now = ktime_get();
		tick_do_update_jiffies64(now);
	}
}


//	切換高分辨率模式
//	函數任務:
//		1.更新clockevent為單觸發模式,安裝高分辨率事件處理程序
//		2.初始化動態時鍾
//			2.1 更新高分辨率激活標誌
//			2.2 更新時鍾基礎為高分辨率標誌
//		3.初始化動態時鍾
//		4.更新tick device到期時間為時鍾基礎中所有hrtimer最短的到期時間
3.1 static int hrtimer_switch_to_hres(void)
{
	int cpu = smp_processor_id();
	struct hrtimer_cpu_base *base = &per_cpu(hrtimer_bases, cpu);
	unsigned long flags;

	local_irq_save(flags);

	//更新clockevent為單觸發模式,安裝高分辨率事件處理程序
	if (tick_init_highres()) {
		local_irq_restore(flags);
		return 0;
	}
	//高分辨率激活標誌
	base->hres_active = 1;
	base->clock_base[CLOCK_REALTIME].resolution = KTIME_HIGH_RES;
	base->clock_base[CLOCK_MONOTONIC].resolution = KTIME_HIGH_RES;
	//初始化動態時鍾
	tick_setup_sched_timer();
	//更新tick device到期時間為時鍾基礎中所有hrtimer最短的到期時間
	retrigger_next_event(NULL);
	local_irq_restore(flags);
	return 1;
}

//	更新clockevnet為單觸發模式,安裝事件處理程序
//	調用路徑:hrtimer_switch_to_hres->tick_switch_to_oneshot
3.2 int tick_init_highres(void)
{
	return tick_switch_to_oneshot(hrtimer_interrupt);
}

//	更新clockevnet為單觸發模式,安裝事件處理程序
//	調用路徑:hrtimer_switch_to_hres->...->tick_switch_to_oneshot
//	函數任務:
//		1.更新設備為單觸發方式
//		2.安裝事件處理程序
//		3.更新廣播設備為單觸發方式
3.3 int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *))
{
	struct tick_device *td = &__get_cpu_var(tick_cpu_device);
	struct clock_event_device *dev = td->evtdev;
	//更新設備為單觸發方式
	td->mode = TICKDEV_MODE_ONESHOT;
	//安裝事件處理程序
	dev->event_handler = handler;
	//編程clockevent設備為單觸發方式
	clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT);
	//切換廣播設備為單觸發方式
	tick_broadcast_switch_to_oneshot();
	return 0;
}

//	初始化動態時鍾
//	調用路徑:hrtimer_switch_to_hres->tick_setup_sched_timer
//	函數任務:
//		1.初始化動態時鍾的hrtimer
//		2.安裝動態時鍾的回調函數
//		3.更新動態時鍾下一個jiffies到期
3.4 void tick_setup_sched_timer(void)
{
	struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
	ktime_t now = ktime_get();
	u64 offset;
	//初始化hrtimer
	hrtimer_init(&ts->sched_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
	//動態時鍾的回調函數
	ts->sched_timer.function = tick_sched_timer;
	//下一個jiffies到期
	hrtimer_set_expires(&ts->sched_timer, tick_init_jiffy_update());
	offset = ktime_to_ns(tick_period) >> 1;
	do_div(offset, num_possible_cpus());
	offset *= smp_processor_id();
	hrtimer_add_expires_ns(&ts->sched_timer, offset);

	//編程啟動動態時鍾
	for (;;) {
		hrtimer_forward(&ts->sched_timer, now, tick_period);
		hrtimer_start_expires(&ts->sched_timer,
				      HRTIMER_MODE_ABS_PINNED);
		if (hrtimer_active(&ts->sched_timer))
			break;
		now = ktime_get();
	}
	....
}

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

  上一篇:go 思維導圖Minimanager9 “參數錯誤”問題
  下一篇:go 劍指Offer之合並兩個排序的鏈表