閱讀434 返回首頁    go 阿裏雲 go 技術社區[雲棲]


時間子係統7_高分辨率定時器處理

//	高分辨率下的定時器軟中斷
//		當增加一個hrtimer到rbtree中後,會raise高分辨率定時器軟中斷
//	函數任務:
//		1.關中斷下,運行所有hrtimer
//	注:
//		在hrtimers_init中,open_softirq(HRTIMER_SOFTIRQ, run_hrtimer_softirq);  
1.1 static void run_hrtimer_softirq(struct softirq_action *h)
{
 	//遍曆運行所有到期的hrtimer
	hrtimer_peek_ahead_timers();
}

//	遍曆運行hrtimer
//	函數任務:
//		1.關中斷
//		2.運行hrtimer
//	調用路徑:run_hrtimer_softirq->hrtimer_peek_ahead_timers
1.2 void hrtimer_peek_ahead_timers(void)
{
	unsigned long flags;
	//關中斷
	local_irq_save(flags);
	hrtimer_interrupt(&__get_cpu_var(tick_cpu_device)->evtdev);
	local_irq_restore(flags);
}

//	高分辨率tick device事件處理函數
//		遍曆執行本cpu上的hrtimer
//	調用路徑:
//		1.run_hrtimer_softirq->....->hrtimer_interrupt 軟中斷路徑。
//		2.當激活高分辨率模式時,安裝此函數作為tick device的事件處理函數。
//	函數任務:
//		1.遍曆時鍾基礎
//			1.1 運行到期的hrtimer
//		2.如果處理完所有hrtimer,關閉時鍾事件設備,退出
//		3.重複步驟1,最多遍曆3次
//		4.更新統計信息
//			4.1 cpu_base->nr_hangs統計一次hrtimer未能處理完所有hrtimer的次數
//			4.2 cpu_base->hang_detected指示有hrtimer待處理
//			4.3 cpu_base->max_hang_time記錄hrtimer_interrupt花費的最大時間,即hrtimer可能被延遲的最大時間
//		5.根據花費的時間計算時鍾事件設備下一次到期的時間
//			5.1 如果處理hrtimer花費時間超過1ms,推遲下一次到期時間為1ms後
//			5.2 否則下一次到期時間為花費的時間
1.3 void hrtimer_interrupt(struct clock_event_device *dev)
{
	struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases);
	struct hrtimer_clock_base *base;
	ktime_t expires_next, now, entry_time, delta;
	int i, retries = 0;

	cpu_base->nr_events++;
	dev->next_event.tv64 = KTIME_MAX;

	entry_time = now = ktime_get();
retry:
	expires_next.tv64 = KTIME_MAX;
	//防止此段時間內其他cpu的hrtimer遷移到本cpu時
	raw_spin_lock(&cpu_base->lock);
	cpu_base->expires_next.tv64 = KTIME_MAX;
	base = cpu_base->clock_base;
	//遍曆所有時鍾基礎的hrtime
	for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
		ktime_t basenow;
		struct rb_node *node;
		//時鍾基礎的時間與實際時間可能有偏移,hrtimer的到期時間為實際時間的絕對值
		basenow = ktime_add(now, base->offset);

		while ((node = base->first)) {
			struct hrtimer *timer;

			timer = rb_entry(node, struct hrtimer, node);
			//如果當前hrtimer還沒有到期
			if (basenow.tv64 < hrtimer_get_softexpires_tv64(timer)) {
				ktime_t expires;
				//更新時鍾事件下一次到期時間
				expires = ktime_sub(hrtimer_get_expires(timer),
						    base->offset);
				if (expires.tv64 < expires_next.tv64)
					expires_next = expires;
				break;
			}
			//否則立即執行定時器
			__run_hrtimer(timer, &basenow);
		}
		base++;
	}

	//更新時鍾基礎下一次到期時間
	cpu_base->expires_next = expires_next;
	raw_spin_unlock(&cpu_base->lock);

	//沒有要到期的hrtimer,關閉時間事件設備
	if (expires_next.tv64 == KTIME_MAX ||
	    !tick_program_event(expires_next, 0)) {
		cpu_base->hang_detected = 0;
		return;
	}

	//防止一直處理hrtimer,最大遍曆次數3
	now = ktime_get();
	cpu_base->nr_retries++;
	if (++retries < 3)
		goto retry;
	//有掛起的hrtimer需要處理
	cpu_base->nr_hangs++;
	cpu_base->hang_detected = 1;
	//計算hrtimer_interrupt處理hrtimer花費的時間
	delta = ktime_sub(now, entry_time);
	if (delta.tv64 > cpu_base->max_hang_time.tv64)
		cpu_base->max_hang_time = delta;
	//根據花費的時間計算時鍾事件設備下一次到期的時間
	//	如果處理hrtimer花費時間超過1ms,推遲下一次到期時間為1ms後
	//	否則下一次到期時間為花費的時間
	if (delta.tv64 > 100 * NSEC_PER_MSEC)
		expires_next = ktime_add_ns(now, 100 * NSEC_PER_MSEC);
	else
		expires_next = ktime_add(now, delta);
	tick_program_event(expires_next, 1);

}
//	運行hrtimer
//	調用路徑:hrtimer_interrupt->__run_hrtimer
//	函數任務:
//		1.從紅黑樹中刪除hrtimer
//		2.設置其為執行狀態
//		3.執行hrtimer回調函數
//			3.1 如果hrtimer需要繼續執行,重新建hrtimer加入到紅黑樹中
//		4.清除其正在執行標誌
1.4 static void __run_hrtimer(struct hrtimer *timer, ktime_t *now)
{
	struct hrtimer_clock_base *base = timer->base;
	struct hrtimer_cpu_base *cpu_base = base->cpu_base;
	enum hrtimer_restart (*fn)(struct hrtimer *);
	int restart;

	//從紅黑樹中刪除hrtimer,設置其為執行狀態
	__remove_hrtimer(timer, base, HRTIMER_STATE_CALLBACK, 0);
	fn = timer->function;

	raw_spin_unlock(&cpu_base->lock);
	//執行hrtimer回調函數
	restart = fn(timer);
	raw_spin_lock(&cpu_base->lock);
	//將hrtimer重新入隊
	if (restart != HRTIMER_NORESTART) {
		enqueue_hrtimer(timer, base);
	}
	//清除其正在執行標誌
	timer->state &= ~HRTIMER_STATE_CALLBACK;
}


//	運行高分辨率定時器
//	調用路徑:
//		update_process_times->run_local_timers->hrtimer_run_queues
//		當沒有開啟高分辨率模式時,高分辨率定時器由低分辨率時鍾軟中斷調用,此函數在低分辨率中銜接高分辨率
//	函數任務:
//		1.檢查高分辨率率定時器框架是否已經被激活
//			1.1 當高分辨率定時器框架被激活時,hrtimer已經通過hrtimer_interrupt被運行
//		2.獲取當前時間
//		3.遍曆時鍾基礎,如果hrtimer到期,運行其回調函數
//	注:
//		當高分辨率率定時器框架為激活時,高分辨率定時器通過時鍾中斷運行,頻率為jiffiy。
2.1 void hrtimer_run_queues(void)
{
	struct timerqueue_node *node;
	struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases);
	struct hrtimer_clock_base *base;
	int index, gettime = 1;
	//如果高分辨率定時器框架已經激活,則hrtimer已經通過hrtimer_interrupt被運行,直接返回
	if (hrtimer_hres_active())
		return;
	//遍曆cpu的時鍾基礎,運行到期的hrtimer
	for (index = 0; index < HRTIMER_MAX_CLOCK_BASES; index++) {
		base = &cpu_base->clock_base[index];
		//當前時鍾基礎已經沒有active的hrtimer,則遍曆下一個
		if (!timerqueue_getnext(&base->active))
			continue;
		//獲取當前時間
		if (gettime) {
			hrtimer_get_softirq_time(cpu_base);
			gettime = 0;
		}

		raw_spin_lock(&cpu_base->lock);
		//獲取下一個active的hrtimer
		while ((node = timerqueue_getnext(&base->active))) {
			struct hrtimer *timer;

			timer = container_of(node, struct hrtimer, node);
			//如果hrtimer到期,則運行其回調函數
			if (base->softirq_time.tv64 <=
					hrtimer_get_expires_tv64(timer))
				break;

			__run_hrtimer(timer, &base->softirq_time);
		}
		raw_spin_unlock(&cpu_base->lock);
	}
}

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

  上一篇:go SQL Server 2005企業版下載一已親自下載安裝,下載速度暴快!
  下一篇:go 思維導圖Minimanager9 “參數錯誤”問題