在前面章節(jié)的討論中,我們一直基于一個(gè)假設(shè):Linux中的時(shí)鐘事件都是由一個(gè)周期時(shí)鐘提供,不管系統(tǒng)中的clock_event_device是工作于周期觸發(fā)模式,還是工作于單觸發(fā)模式,也不管定時(shí)器系統(tǒng)是工作于低分辨率模式,還是高精度模式,內(nèi)核都竭盡所能,用不同的方式提供周期時(shí)鐘,以產(chǎn)生定期的tick事件,tick事件或者用于全局的時(shí)間管理(jiffies和時(shí)間的更新),或者用于本地cpu的進(jìn)程統(tǒng)計(jì)、時(shí)間輪定時(shí)器框架等等。周期性時(shí)鐘雖然簡(jiǎn)單有效,但是也帶來了一些缺點(diǎn),尤其在系統(tǒng)的功耗上,因?yàn)榫退阆到y(tǒng)目前無事可做,也必須定期地發(fā)出時(shí)鐘事件,激活系統(tǒng)。為此,內(nèi)核的開發(fā)者提出了動(dòng)態(tài)時(shí)鐘這一概念,我們可以通過內(nèi)核的配置項(xiàng)CONFIG_NO_HZ來激活特性。有時(shí)候這一特性也被叫做tickless,不過還是把它稱呼為動(dòng)態(tài)時(shí)鐘比較合適,因?yàn)椴⒉皇钦娴臎]有tick事件了,只是在系統(tǒng)無事所做的idle階段,我們可以通過停止周期時(shí)鐘來達(dá)到降低系統(tǒng)功耗的目的,只要有進(jìn)程處于活動(dòng)狀態(tài),時(shí)鐘事件依然會(huì)被周期性地發(fā)出。
在動(dòng)態(tài)時(shí)鐘正確工作之前,系統(tǒng)需要切換至動(dòng)態(tài)時(shí)鐘模式,而要切換至動(dòng)態(tài)時(shí)鐘模式,需要一些前提條件,最主要的一條就是cpu的時(shí)鐘事件設(shè)備必須要支持單觸發(fā)模式,當(dāng)條件滿足時(shí),系統(tǒng)切換至動(dòng)態(tài)時(shí)鐘模式,接著,由idle進(jìn)程決定是否可以停止周期時(shí)鐘,退出idle進(jìn)程時(shí)則需要恢復(fù)周期時(shí)鐘。
1. ?數(shù)據(jù)結(jié)構(gòu)
在上一章的內(nèi)容里,我們?cè)?jīng)提到,切換到高精度模式后,高精度定時(shí)器系統(tǒng)需要使用一個(gè)高精度定時(shí)器來模擬傳統(tǒng)的周期時(shí)鐘,其中利用了tick_sched結(jié)構(gòu)中的一些字段,事實(shí)上,tick_sched結(jié)構(gòu)也是實(shí)現(xiàn)動(dòng)態(tài)時(shí)鐘的一個(gè)重要的數(shù)據(jù)結(jié)構(gòu),在smp系統(tǒng)中,內(nèi)核會(huì)為每個(gè)cpu都定義一個(gè)tick_sched結(jié)構(gòu),這通過一個(gè)percpu全局變量tick_cpu_sched來實(shí)現(xiàn),它在kernel/time/tick-sched.c中定義:
[cpp]?view plain?copy
/*?
*?Per?cpu?nohz?control?structure?
*/??
static?DEFINE_PER_CPU(struct?tick_sched,?tick_cpu_sched);??
tick_sched結(jié)構(gòu)在include/linux/tick.h中定義,我們看看tick_sched結(jié)構(gòu)的詳細(xì)定義:
[cpp]?view plain?copy
struct?tick_sched?{??
struct?hrtimer??????????sched_timer;??
unsigned?long???????????check_clocks;??
enum?tick_nohz_mode?????nohz_mode;??
ktime_t?????????????idle_tick;??
int?????????????inidle;??
int?????????????tick_stopped;??
unsigned?long???????????idle_jiffies;??
unsigned?long???????????idle_calls;??
unsigned?long???????????idle_sleeps;??
int?????????????idle_active;??
ktime_t?????????????idle_entrytime;??
ktime_t?????????????idle_waketime;??
ktime_t?????????????idle_exittime;??
ktime_t?????????????idle_sleeptime;??
ktime_t?????????????iowait_sleeptime;??
ktime_t?????????????sleep_length;??
unsigned?long???????????last_jiffies;??
unsigned?long???????????next_jiffies;??
ktime_t?????????????idle_expires;??
int?????????????do_timer_last;??
};??
sched_timer? 該字段用于在高精度模式下,模擬周期時(shí)鐘的一個(gè)hrtimer,請(qǐng)參看Linux時(shí)間子系統(tǒng)之六:高精度定時(shí)器(HRTIMER)的原理和實(shí)現(xiàn)。
check_clocks? 該字段用于實(shí)現(xiàn)clock_event_device和clocksource的異步通知機(jī)制,幫助系統(tǒng)切換至高精度模式或者是動(dòng)態(tài)時(shí)鐘模式。
nohz_mode? 保存動(dòng)態(tài)時(shí)鐘的工作模式,基于低分辨率和高精度模式下,動(dòng)態(tài)時(shí)鐘的實(shí)現(xiàn)稍有不同,根據(jù)模式它可以是以下的值:
NOHZ_MODE_INACTIVE ?系統(tǒng)動(dòng)態(tài)時(shí)鐘尚未激活
NOHZ_MODE_LOWRES ?系統(tǒng)工作于低分辨率模式下的動(dòng)態(tài)時(shí)鐘
NOHZ_MODE_HIGHRES ?系統(tǒng)工作于高精度模式下的動(dòng)態(tài)時(shí)鐘
idle_tick? 該字段用于保存停止周期時(shí)鐘是的內(nèi)核時(shí)間,當(dāng)退出idle時(shí)要恢復(fù)周期時(shí)鐘,需要使用該時(shí)間,以保持系統(tǒng)中時(shí)間線(jiffies)的正確性。
tick_stopped? 該字段用于表明idle狀態(tài)的周期時(shí)鐘已經(jīng)停止。
idle_jiffies? 系統(tǒng)進(jìn)入idle時(shí)的jiffies值,用于信息統(tǒng)計(jì)。
idle_calls?系統(tǒng)進(jìn)入idle的統(tǒng)計(jì)次數(shù)。
idle_sleeps? 系統(tǒng)進(jìn)入idle且成功停掉周期時(shí)鐘的次數(shù)。
idle_active? 表明目前系統(tǒng)是否處于idle狀態(tài)中。
idle_entrytime? 系統(tǒng)進(jìn)入idle的時(shí)刻。
idle_waketime? idle狀態(tài)被打斷的時(shí)刻。
idle_exittime??系統(tǒng)退出idle的時(shí)刻。
idle_sleeptime? 累計(jì)各次idle中停止周期時(shí)鐘的總時(shí)間。
sleep_length? 本次idle中停止周期時(shí)鐘的時(shí)間。
last_jiffies? 系統(tǒng)中最后一次周期時(shí)鐘的jiffies值。
next_jiffies? 預(yù)計(jì)下一次周期時(shí)鐘的jiffies。
idle_expires? 進(jìn)入idle后,下一個(gè)最先到期的定時(shí)器時(shí)刻。
我們知道,根據(jù)系統(tǒng)目前的工作模式,系統(tǒng)提供周期時(shí)鐘(tick)的方式會(huì)有所不同,當(dāng)處于低分辨率模式時(shí),由cpu的tick_device提供周期時(shí)鐘,而當(dāng)處于高精度模式時(shí),是由一個(gè)高精度定時(shí)器來提供周期時(shí)鐘,下面我們分別討論一下在兩種模式下的動(dòng)態(tài)時(shí)鐘實(shí)現(xiàn)方式。
2. ?低分辨率下的動(dòng)態(tài)時(shí)鐘
回看之前一篇文章:Linux時(shí)間子系統(tǒng)之四:定時(shí)器的引擎:clock_event_device中的關(guān)于tick_device一節(jié),不管tick_device的工作模式(周期觸發(fā)或者是單次觸發(fā)),tick_device所關(guān)聯(lián)的clock_event_device的事件回調(diào)處理函數(shù)都是:tick_handle_periodic,不管當(dāng)前是否處于idle狀態(tài),他都會(huì)精確地按HZ數(shù)來提供周期性的tick事件,這不符合動(dòng)態(tài)時(shí)鐘的要求,所以,要使動(dòng)態(tài)時(shí)鐘發(fā)揮作用,系統(tǒng)首先要切換至支持動(dòng)態(tài)時(shí)鐘的工作模式:NOHZ_MODE_LOWRES ?。
2.1 ?切換至動(dòng)態(tài)時(shí)鐘模式
動(dòng)態(tài)時(shí)鐘模式的切換過程的前半部分和切換至高精度定時(shí)器模式所經(jīng)過的路徑是一樣的,請(qǐng)參考:Linux時(shí)間子系統(tǒng)之六:高精度定時(shí)器(HRTIMER)的原理和實(shí)現(xiàn)。這里再簡(jiǎn)單描述一下過程:系統(tǒng)工作于周期時(shí)鐘模式,定期地發(fā)出tick事件中斷,tick事件中斷觸發(fā)定時(shí)器軟中斷:TIMER_SOFTIRQ,執(zhí)行軟中斷處理函數(shù)run_timer_softirq,run_timer_softirq調(diào)用hrtimer_run_pending函數(shù):
[cpp]?view plain?copy
void?hrtimer_run_pending(void)??
{??
if?(hrtimer_hres_active())??
return;??
......??
if?(tick_check_oneshot_change(!hrtimer_is_hres_enabled()))??
hrtimer_switch_to_hres();??
}??
tick_check_oneshot_change函數(shù)的參數(shù)決定了現(xiàn)在是要切換至低分辨率動(dòng)態(tài)時(shí)鐘模式,還是高精度定時(shí)器模式,我們現(xiàn)在假設(shè)系統(tǒng)不支持高精度定時(shí)器模式,hrtimer_is_hres_enabled會(huì)直接返回false,對(duì)應(yīng)的tick_check_oneshot_change函數(shù)的參數(shù)則是true,表明需要切換至動(dòng)態(tài)時(shí)鐘模式。tick_check_oneshot_change在檢查過timekeeper和clock_event_device都具備動(dòng)態(tài)時(shí)鐘的條件后,通過tick_nohz_switch_to_nohz函數(shù)切換至動(dòng)態(tài)時(shí)鐘模式:
首先,該函數(shù)通過tick_switch_to_oneshot函數(shù)把tick_device的工作模式設(shè)置為單觸發(fā)模式,并把它的中斷事件回調(diào)函數(shù)置換為tick_nohz_handler,接著把tick_sched結(jié)構(gòu)中的模式字段設(shè)置為NOHZ_MODE_LOWRES:
[cpp]?view plain?copy
static?void?tick_nohz_switch_to_nohz(void)??
{??
struct?tick_sched?*ts?=?&__get_cpu_var(tick_cpu_sched);??
ktime_t?next;??
if?(!tick_nohz_enabled)??
return;??
local_irq_disable();??
if?(tick_switch_to_oneshot(tick_nohz_handler))?{??
local_irq_enable();??
return;??
}??
ts->nohz_mode?=?NOHZ_MODE_LOWRES;??
然后,初始化tick_sched結(jié)構(gòu)中的sched_timer定時(shí)器,通過tick_init_jiffy_update獲取下一次tick事件的時(shí)間并初始化全局變量last_jiffies_update,以便后續(xù)可以正確地更新jiffies計(jì)數(shù)值,最后,把下一次tick事件的時(shí)間編程到tick_device中,到此,系統(tǒng)完成了到低分辨率動(dòng)態(tài)時(shí)鐘的切換過程。
[cpp]?view plain?copy
hrtimer_init(&ts->sched_timer,?CLOCK_MONOTONIC,?HRTIMER_MODE_ABS);??
/*?Get?the?next?period?*/??
next?=?tick_init_jiffy_update();??
for?(;;)?{??
hrtimer_set_expires(&ts->sched_timer,?next);??
if?(!tick_program_event(next,?0))??
break;??
next?=?ktime_add(next,?tick_period);??
}??
local_irq_enable();??
}??
上面的代碼中,明明現(xiàn)在沒有切換至高精度模式,為什么要初始化tick_sched結(jié)構(gòu)中的高精度定時(shí)器?原因并不是要使用它的定時(shí)功能,而是想重用hrtimer代碼中的hrtimer_forward函數(shù),利用這個(gè)函數(shù)來計(jì)算下一次tick事件的時(shí)間。
2.2 ?低分辨率動(dòng)態(tài)時(shí)鐘下的事件中斷處理函數(shù)
上一節(jié)提到,當(dāng)切換至低分辨率動(dòng)態(tài)時(shí)鐘模式后,tick_device的事件中斷處理函數(shù)會(huì)被設(shè)置為tick_nohz_handler,總體來說,它和周期時(shí)鐘模式的事件處理函數(shù)tick_handle_periodic所完成的工作大致類似:更新時(shí)間、更新jiffies計(jì)數(shù)值、調(diào)用update_process_time更新進(jìn)程信息和觸發(fā)定時(shí)器軟中斷等等,最后重新編程tick_device,使得它在下一個(gè)正確的tick時(shí)刻再次觸發(fā)本函數(shù):
[cpp]?view plain?copy
static?void?tick_nohz_handler(struct?clock_event_device?*dev)??
{??
......??
dev->next_event.tv64?=?KTIME_MAX;??
if?(unlikely(tick_do_timer_cpu?==?TICK_DO_TIMER_NONE))??
tick_do_timer_cpu?=?cpu;??
/*?Check,?if?the?jiffies?need?an?update?*/??
if?(tick_do_timer_cpu?==?cpu)??
tick_do_update_jiffies64(now);??
......????
if?(ts->tick_stopped)?{??
touch_softlockup_watchdog();??
ts->idle_jiffies++;??
}??
update_process_times(user_mode(regs));??
profile_tick(CPU_PROFILING);??
while?(tick_nohz_reprogram(ts,?now))?{??
now?=?ktime_get();??
tick_do_update_jiffies64(now);??
}??
}??
因?yàn)楝F(xiàn)在工作于動(dòng)態(tài)時(shí)鐘模式,所以,tick時(shí)鐘可能在idle進(jìn)程中被停掉不止一個(gè)tick周期,所以當(dāng)該函數(shù)被再次觸發(fā)時(shí),離上一次觸發(fā)的時(shí)間可能已經(jīng)不止一個(gè)tick周期,tick_nohz_reprogram對(duì)tick_device進(jìn)行編程時(shí)必須正確地處理這一情況,它利用了前面所說的hrtimer_forward函數(shù)來實(shí)現(xiàn)這一特性:
[cpp]?view plain?copy
static?int?tick_nohz_reprogram(struct?tick_sched?*ts,?ktime_t?now)??
{??
hrtimer_forward(&ts->sched_timer,?now,?tick_period);??
return?tick_program_event(hrtimer_get_expires(&ts->sched_timer),?0);??
}??
2.3 ?動(dòng)態(tài)時(shí)鐘:停止周期tick時(shí)鐘事件
開啟動(dòng)態(tài)時(shí)鐘模式后,周期時(shí)鐘的開啟和關(guān)閉由idle進(jìn)程控制,idle進(jìn)程內(nèi)最終是一個(gè)循環(huán),循環(huán)的一開始通過tick_nohz_idle_enter檢測(cè)是否允許關(guān)閉周期時(shí)鐘若干時(shí)間,然后進(jìn)入低功耗的idle模式,當(dāng)有中斷事件使得cpu退出低功耗idle模式后,判斷是否有新的進(jìn)程被激活從而需要重新調(diào)度,如果需要?jiǎng)t通過tick_nohz_idle_exit重新啟用周期時(shí)鐘,然后重新進(jìn)行進(jìn)程調(diào)度,等待下一次idle的發(fā)生,我們可以用下圖來表示:
圖2.3.1 ?idle進(jìn)程中的動(dòng)態(tài)時(shí)鐘處理
停止周期時(shí)鐘的時(shí)機(jī)在tick_nohz_idle_enter函數(shù)中,它把主要的工作交由tick_nohz_stop_sched_tick函數(shù)來完成。內(nèi)核也不是每次進(jìn)入tick_nohz_stop_sched_tick都會(huì)停止周期時(shí)鐘,那么什么時(shí)候才會(huì)停止?我們想一想,這時(shí)候既然idle進(jìn)程在運(yùn)行,說明系統(tǒng)中的其他進(jìn)程都在等待某種事件,系統(tǒng)處于無事所做的狀態(tài),唯一要處理的就是中斷,除了定時(shí)器中斷,其它的中斷我們無法預(yù)測(cè)它會(huì)何時(shí)發(fā)生,但是我們可以知道最先一個(gè)到期的定時(shí)器的到期時(shí)間,也就是說,在該時(shí)間到期前,產(chǎn)生周期時(shí)鐘是沒有必要的,我們可以據(jù)此推算出周期時(shí)鐘可以停止的tick數(shù),然后重新對(duì)tick_device進(jìn)行編程,使得在最早一個(gè)定時(shí)器到期前都不會(huì)產(chǎn)生周期時(shí)鐘,實(shí)際上,tick_nohz_stop_sched_tick還做了一些限制:當(dāng)下一個(gè)定時(shí)器的到期時(shí)間與當(dāng)前jiffies值只相差1時(shí),不會(huì)停止周期時(shí)鐘,當(dāng)定時(shí)器的到期時(shí)間與當(dāng)前的jiffies值相差的時(shí)間大于timekeeper允許的最大idle時(shí)間時(shí),則下一個(gè)tick時(shí)刻被設(shè)置timekeeper允許的最大idle時(shí)間,這主要是為了防止太長(zhǎng)時(shí)間不去更新timekeeper中的系統(tǒng)時(shí)間,有可能導(dǎo)致clocksource的溢出問題。tick_nohz_stop_sched_tick函數(shù)體看起來很長(zhǎng),實(shí)現(xiàn)的也就是上述的邏輯,所以這里就不貼它的代碼了,有興趣的讀者可以自行閱讀內(nèi)核的代碼:kernel/time/tick-sched.c。
看了動(dòng)態(tài)時(shí)鐘的停止過程和tick_nohz_handler的實(shí)現(xiàn)方式,其實(shí)還有一個(gè)情況沒有處理:當(dāng)系統(tǒng)進(jìn)入idle進(jìn)程后,周期時(shí)鐘被停止若干個(gè)tick周期,當(dāng)這若干個(gè)tick周期到期后,tick事件必然會(huì)產(chǎn)生,tick_nohz_handler被觸發(fā)調(diào)用,然后最先到期的定時(shí)器被處理。但是在tick_nohz_handler的最后,tick_device一定會(huì)被編程為緊跟著的下一個(gè)tick周期的時(shí)刻被觸發(fā),如果剛才的定時(shí)器處理后,并沒有激活新的進(jìn)程,我們的期望是周期時(shí)鐘可以用下一個(gè)新的定時(shí)器重新計(jì)算可以停止的時(shí)間,而不是下一個(gè)tick時(shí)刻,但是tick_nohz_handler卻僅僅簡(jiǎn)單地把tick_device的到期時(shí)間設(shè)為下一個(gè)周期的tick時(shí)刻,這導(dǎo)致了周期時(shí)鐘被恢復(fù),顯然這不是我們想要的。為了處理這種情況,內(nèi)核使用了一點(diǎn)小伎倆,我們知道定時(shí)器是在軟中斷中執(zhí)行的,所以內(nèi)核在irq_exit中的軟件中斷處理完后,加入了一小段代碼,kernel/softirq.c :
[cpp]?view plain?copy
void?irq_exit(void)??
{??
......??
if?(!in_interrupt()?&&?local_softirq_pending())??
invoke_softirq();??
#ifdef?CONFIG_NO_HZ??
/*?Make?sure?that?timer?wheel?updates?are?propagated?*/??
if?(idle_cpu(smp_processor_id())?&&?!in_interrupt()?&&?!need_resched())??
tick_nohz_irq_exit();??
#endif??
......??
}??
關(guān)鍵的調(diào)用是tick_nohz_irq_exit:
[cpp]?view plain?copy
void?tick_nohz_irq_exit(void)??
{??
struct?tick_sched?*ts?=?&__get_cpu_var(tick_cpu_sched);??
if?(!ts->inidle)??
return;??
tick_nohz_stop_sched_tick(ts);??
}??
tick_nohz_irq_exit再次調(diào)用了tick_nohz_stop_sched_tick函數(shù),使得系統(tǒng)有機(jī)會(huì)再次停止周期時(shí)鐘若干個(gè)tick周期。
2.3 ?動(dòng)態(tài)時(shí)鐘:重新開啟周期tick時(shí)鐘事件
回到圖2.3.1,當(dāng)在idle進(jìn)程中停止周期時(shí)鐘后,在某一時(shí)刻,有新的進(jìn)程被激活,在重新調(diào)度前,tick_nohz_idle_exit會(huì)被調(diào)用,該函數(shù)負(fù)責(zé)恢復(fù)被停止的周期時(shí)鐘。tick_nohz_idle_exit最終會(huì)調(diào)用tick_nohz_restart函數(shù),由tick_nohz_restart函數(shù)最后完成恢復(fù)周期時(shí)鐘的工作。函數(shù)并不復(fù)雜:先是把上一次停止周期時(shí)鐘的時(shí)刻設(shè)置到tick_sched結(jié)構(gòu)的sched_timer定時(shí)器中,然后在通過hrtimer_forward函數(shù)把該定時(shí)器的到期時(shí)刻設(shè)置為當(dāng)前時(shí)間的下一個(gè)tick時(shí)刻,對(duì)于高精度模式,啟動(dòng)該定時(shí)器即可,對(duì)于低分辨率模式,使用該時(shí)間對(duì)tick_device重新編程,最后通過tick_do_update_jiffies64更新jiffies數(shù)值,為了防止此時(shí)正在一個(gè)tick時(shí)刻的邊界,可能當(dāng)前時(shí)刻正好剛剛越過了該到期時(shí)間,函數(shù)使用了一個(gè)while循環(huán):
[cpp]?view plain?copy
static?void?tick_nohz_restart(struct?tick_sched?*ts,?ktime_t?now)??
{??
hrtimer_cancel(&ts->sched_timer);??
hrtimer_set_expires(&ts->sched_timer,?ts->idle_tick);??
while?(1)?{??
/*?Forward?the?time?to?expire?in?the?future?*/??
hrtimer_forward(&ts->sched_timer,?now,?tick_period);??
if?(ts->nohz_mode?==?NOHZ_MODE_HIGHRES)?{??
hrtimer_start_expires(&ts->sched_timer,??
HRTIMER_MODE_ABS_PINNED);??
/*?Check,?if?the?timer?was?already?in?the?past?*/??
if?(hrtimer_active(&ts->sched_timer))??
break;??
}?else?{??
if?(!tick_program_event(??
hrtimer_get_expires(&ts->sched_timer),?0))??
break;??
}??
/*?Reread?time?and?update?jiffies?*/??
now?=?ktime_get();??
tick_do_update_jiffies64(now);??
}??
}??
3. ?高精度模式下的動(dòng)態(tài)時(shí)鐘
高精度模式和低分辨率模式的主要區(qū)別是在切換過程中,怎樣切換到高精度模式,我已經(jīng)在上一篇文章中做了說明,切換到高精度模式后,動(dòng)態(tài)時(shí)鐘的開啟和關(guān)閉和低分辨率模式下沒有太大的區(qū)別,也是通過tick_nohz_stop_sched_tick和tick_nohz_restart來控制,在這兩個(gè)函數(shù)中,分別判斷了當(dāng)前的兩種模式:
NOHZ_MODE_HIGHRES
NOHZ_MODE_LOWRES
如果是NOHZ_MODE_HIGHRES則對(duì)tick_sched結(jié)構(gòu)的sched_timer定時(shí)器進(jìn)行設(shè)置,如果是NOHZ_MODE_LOWRES,則直接對(duì)tick_device進(jìn)行操作。
4. ?動(dòng)態(tài)時(shí)鐘對(duì)中斷的影響
在進(jìn)入和退出中斷時(shí),因?yàn)閯?dòng)態(tài)時(shí)鐘的關(guān)系,中斷系統(tǒng)需要作出一些配合。先說中斷發(fā)生于周期時(shí)鐘停止期間,如果不做任何處理,中斷服務(wù)程序中如果要訪問jiffies計(jì)數(shù)值,可能得到一個(gè)滯后的jiffies值,因?yàn)檎顟B(tài)下,jiffies值會(huì)在恢復(fù)周期時(shí)鐘時(shí)正確地更新,所以,為了防止這種情況發(fā)生,在進(jìn)入中斷的irq_enter期間,tick_check_idle會(huì)被調(diào)用:
[cpp]?view plain?copy
void?tick_check_idle(int?cpu)??
{??
tick_check_oneshot_broadcast(cpu);??
tick_check_nohz(cpu);??
}??
tick_check_nohz函數(shù)的最重要的作用就是更新jiffies計(jì)數(shù)值:
[cpp]?view plain?copy
static?inline?void?tick_check_nohz(int?cpu)??
{??
struct?tick_sched?*ts?=?&per_cpu(tick_cpu_sched,?cpu);??
ktime_t?now;??
if?(!ts->idle_active?&&?!ts->tick_stopped)??
return;??
now?=?ktime_get();??
if?(ts->idle_active)??
tick_nohz_stop_idle(cpu,?now);??
if?(ts->tick_stopped)?{??
tick_nohz_update_jiffies(now);??
tick_nohz_kick_tick(cpu,?now);??
}??
}??
另外一種情況是在退出定時(shí)器中斷時(shí),需要重新評(píng)估周期時(shí)鐘的運(yùn)行狀況,這一點(diǎn)已經(jīng)在2.3節(jié)中做了說明,這里就不在贅述了。
?
評(píng)論