分析linux內(nèi)核的idle的知識
Linux系統(tǒng)越來越受到電腦用戶的歡迎,于是很多人開始學(xué)習(xí)Linux時,學(xué)習(xí)linux,你可能會遇到linux內(nèi)核問題,這里將介紹linux內(nèi)核中idle知識,在這里拿出來和大家分享一下。
1. idle是什么
簡單的說idle是一個進(jìn)程,其pid號為 0。其前身是系統(tǒng)創(chuàng)建的第一個進(jìn)程,也是唯一一個沒有通過fork()產(chǎn)生的進(jìn)程。在smp系統(tǒng)中,每個處理器單元有獨立的一個運行隊列,而每個運行隊列上又有一個idle進(jìn)程,即有多少處理器單元,就有多少idle進(jìn)程。系統(tǒng)的空閑時間,其實就是指idle進(jìn)程的"運行時間"。既然是idle是進(jìn)程,那我們來看看idle是如何被創(chuàng)建,又具體做了哪些事情?
2. idle的創(chuàng)建
我們知道系統(tǒng)是從BIOS加電自檢,載入MBR中的引導(dǎo)程序(LILO/GRUB),再加載linux內(nèi)核開始運行的,一直到指定shell開始運行告一段落,這時用戶開始操作Linux。而大致是在vmlinux的入口startup_32(head.S)中為pid號為0的原始進(jìn)程設(shè)置了執(zhí)行環(huán)境,然后原是進(jìn)程開始執(zhí)行start_kernel()完成Linux內(nèi)核的初始化工作。包括初始化頁表,初始化中斷向量表,初始化系統(tǒng)時間等。繼而調(diào)用 fork(),創(chuàng)建第一個用戶進(jìn)程:
kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
這個進(jìn)程就是著名的pid為1的init進(jìn)程,它會繼續(xù)完成剩下的初始化工作,然后execve(/sbin/init), 成為系統(tǒng)中的其他所有進(jìn)程的祖先。關(guān)于init我們這次先不研究,回過頭來看pid=0的進(jìn)程,在創(chuàng)建了init進(jìn)程后,pid=0的進(jìn)程調(diào)用 cpu_idle()演變成了idle進(jìn)程。
current_thread_info()->status |= TS_POLLING;
在 smp系統(tǒng)中,除了上面剛才我們講的主處理器(執(zhí)行初始化工作的處理器)上idle進(jìn)程的創(chuàng)建,還有從處理器(被主處理器activate的處理器)上的idle進(jìn)程,他們又是怎么創(chuàng)建的呢?接著看init進(jìn)程,init在演變成/sbin/init之前,會執(zhí)行一部分初始化工作,其中一個就是 smp_prepare_cpus(),初始化SMP處理器,在這過程中會在處理每個從處理器時調(diào)用
task = copy_process(CLONE_VM, 0, idle_regs(®s), 0, NULL, NULL, 0);
init_idle(task, cpu);
即從init中復(fù)制出一個進(jìn)程,并把它初始化為idle進(jìn)程(pid仍然為0)。從處理器上的idle進(jìn)程會進(jìn)行一些Activate工作,然后執(zhí)行cpu_idle()。
整個過程簡單的說就是,原始進(jìn)程(pid=0)創(chuàng)建init進(jìn)程(pid=1),然后演化成idle進(jìn)程(pid=0)。init進(jìn)程為每個從處理器(運行隊列)創(chuàng)建出一個idle進(jìn)程(pid=0),然后演化成/sbin/init。
3. idle的運行時機(jī)
idle 進(jìn)程優(yōu)先級為MAX_PRIO,即最低優(yōu)先級。早先版本中,idle是參與調(diào)度的,所以將其優(yōu)先級設(shè)為最低,當(dāng)沒有其他進(jìn)程可以運行時,才會調(diào)度執(zhí)行idle。而目前的版本中idle并不在運行隊列中參與調(diào)度,而是在運行隊列結(jié)構(gòu)中含idle指針,指向idle進(jìn)程,在調(diào)度器發(fā)現(xiàn)運行隊列為空的時候運行,調(diào)入運行。
4. idle的workload
從上面的分析我們可以看出,idle在系統(tǒng)沒有其他就緒的進(jìn)程可執(zhí)行的時候才會被調(diào)度。不管是主處理器,還是從處理器,最后都是執(zhí)行的cpu_idle()函數(shù)。所以我們來看看cpu_idle做了什么事情。
因為idle進(jìn)程中并不執(zhí)行什么有意義的任務(wù),所以通??紤]的是兩點:1.節(jié)能,2.低退出延遲。
其核心代碼如下:
- void cpu_idle(void)
- {
- int cpu = smp_processor_id();
- current_thread_info()->status |= TS_POLLING;
- /* endless idle loop with no priority at all */
- while (1) {
- tick_nohz_stop_sched_tick(1);
- while (!need_resched()) {
- check_pgt_cache();
- rmb();
- if (rcu_pending(cpu))
- rcu_check_callbacks(cpu, 0);
- if (cpu_is_offline(cpu))
- play_dead();
- local_irq_disable();
- __get_cpu_var(irq_stat).idle_timestamp = jiffies;
- /* Don't trace irqs off for idle */
- stop_critical_timings();
- pm_idle();
- start_critical_timings();
- }
- tick_nohz_restart_sched_tick();
- preempt_enable_no_resched();
- schedule();
- preempt_disable();
- }
- }
循環(huán)判斷need_resched以降低退出延遲,用idle()來節(jié)能。
默認(rèn)的idle實現(xiàn)是hlt指令,hlt指令使CPU處于暫停狀態(tài),等待硬件中斷發(fā)生的時候恢復(fù),從而達(dá)到節(jié)能的目的。即從處理器C0態(tài)變到C1態(tài)(見 ACPI標(biāo)準(zhǔn))。這也是早些年windows平臺上各種"處理器降溫"工具的主要手段。當(dāng)然idle也可以是在別的ACPI或者APM模塊中定義的,甚至是自定義的一個idle(比如說nop)。
小結(jié):
1.idle是一個進(jìn)程,其pid為0。
2.主處理器上的idle由原始進(jìn)程(pid=0)演變而來。從處理器上的idle由init進(jìn)程fork得到,但是它們的pid都為0。
3.Idle進(jìn)程為最低優(yōu)先級,且不參與調(diào)度,只是在運行隊列為空的時候才被調(diào)度。
4.Idle循環(huán)等待need_resched置位。默認(rèn)使用hlt節(jié)能。
希望通過本文你能全面了解linux內(nèi)核中idle知識。
【編輯推薦】