日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux内核rest_init分析

發(fā)布時間:2025/3/15 linux 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux内核rest_init分析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

代碼在start_kernel函數(shù)運行的最后到了rest_init()函數(shù)中

?

1:rest_init()函數(shù)分析

? (1)rest_init中調(diào)用kernel_thread函數(shù)啟動了2個內(nèi)核線程,分別是:kernel_init和kthreadd

? (2)調(diào)用schedule函數(shù)開啟了內(nèi)核的調(diào)度系統(tǒng),從此linux系統(tǒng)開始轉(zhuǎn)起來了。

? (3)rest_init最終調(diào)用cpu_idle函數(shù)結(jié)束了整個內(nèi)核的啟動。也就是說linux內(nèi)核最終結(jié)束了一個函數(shù)cpu_idle。這個函數(shù)里面肯定是死循環(huán)。

? (4)簡單來說,linux內(nèi)核最終的狀態(tài)是:有事干的時候去執(zhí)行有意義的工作(執(zhí)行各個進程任務(wù)),實在沒活干的時候就去死循環(huán)(實際上死循環(huán)也可以看成是一個任務(wù))。

? (5)之前已經(jīng)啟動了內(nèi)核調(diào)度系統(tǒng),調(diào)度系統(tǒng)會負責(zé)考評系統(tǒng)中所有的進程,這些進程里面只有有哪個需要被運行,調(diào)度系統(tǒng)就會終止cpu_idle死循環(huán)進程(空閑進程)轉(zhuǎn)而去執(zhí)行有意義的干活的進程。這樣操作系統(tǒng)就轉(zhuǎn)起來了。

?

2.1:什么是內(nèi)核線程

? (1)進程和線程。簡單來理解,一個運行的程序就是一個進程。所以進程就是任務(wù)、進程就是一個獨立的程序。

獨立的意思就是這個程序和別的程序是分開的,這個程序可以被內(nèi)核單獨調(diào)用執(zhí)行或者暫停。

? (2)在linux系統(tǒng)中,線程和進程非常相似,幾乎可以看成是一樣的。實際上我們當(dāng)前講課用到的進程和線程的概念就是

一樣的。

? (3)進程/線程就是一個獨立的程序。應(yīng)用層運行一個程序就構(gòu)成一個用戶進程/線程,那么內(nèi)核中運行

一個函數(shù)(函數(shù)其實就是一個程序)就構(gòu)成了一個內(nèi)核進程/線程。

? (4)所以我們kernel_thead函數(shù)運行一個函數(shù),其實就是把這個函數(shù)變成了一個內(nèi)核線程去運行起來,然后他可以被內(nèi)核調(diào)度系統(tǒng)去調(diào)度。說白了就是去調(diào)度器注冊了一下,以后人家調(diào)度的時候會考慮你。

?

2.2:進程0、進程1、進程2

?(1)操作系統(tǒng)是用一個數(shù)字來表示/記錄一個進程/線程的,這個數(shù)字就被稱為這個進程的進程號。這個號碼是從0開始分配的。因此這里涉及到的三個進程分別是linux系統(tǒng)的進程0、進程1、進程2.

?(2)在linux命令行下,使用ps命令可以查看當(dāng)前l(fā)inux系統(tǒng)中運行的進程情況。

(4)我們在ubuntu下ps -aux可以看到當(dāng)前系統(tǒng)運行的所有進程,可以看出進程號是從1開始的。為什么不從0開始,因為進程0不是一個用戶進程,而屬于內(nèi)核進程。

? 進程0:進程0其實就是剛才講過的idle進程,叫空閑進程,也就是死循環(huán)。

? 進程1:kernel_init函數(shù)就是進程1,這個進程被稱為init進程。

? 進程2:kthreadd函數(shù)就是進程2,這個進程是linux內(nèi)核的守護進程。它的作用是管理調(diào)度其他內(nèi)核進程這個進程是用來保證linux內(nèi)核自己本身能正常工作的。

?

3:init進程分析

? 需要注意的一點是這個進程剛開始運行的時候是內(nèi)核態(tài),是屬于內(nèi)核進程,然后它自己運行了一個用戶太下面的程序后把自己強行轉(zhuǎn)成了用戶態(tài),因為init進程自身完成了從內(nèi)核態(tài)到用戶態(tài)的過渡,所以后續(xù)的其他進程都可以工作在用戶態(tài)下面了

?

3.1:init進程在內(nèi)核態(tài)下做了什么

? 重要的點就掛載根文件系統(tǒng),并試圖找到用戶態(tài)下的那個init程序,原因是init進程要完成從內(nèi)核態(tài)到用戶態(tài)的轉(zhuǎn)變就必須去運行一個用戶態(tài)的應(yīng)用程序,而內(nèi)核源代碼中的程序都是屬于內(nèi)核態(tài)的,所以這個應(yīng)用程序必須不屬于內(nèi)核源代碼,這樣才能保證自己是用戶態(tài),所以這個應(yīng)用程序就的是由另外一份文件提供,即根文件系統(tǒng)

3.2: init進程在用戶態(tài)下做了什么

? init進程大部分有意義的工作都是在用戶態(tài)下進行的,原因是用戶態(tài)下的所有進程都是直接或者間接由init進程生成的。

3.3:如何從內(nèi)核態(tài)跳躍到用戶態(tài)?還能回來不?

? init進程在內(nèi)核態(tài)下面時,通過調(diào)用kernel_execve函數(shù)來執(zhí)行一個用戶空間編譯鏈接的應(yīng)用程序就跳躍到了用戶態(tài)下面了,需要注意的是,這個跳躍的過程進程號并沒有改變還是進程1,并且這個跳躍是單向的,以后要從用戶態(tài)回到內(nèi)核態(tài)只有走API這一條路了

kernel_execve函數(shù)被調(diào)用的路徑start_kernel->rest_init->kernel_thread->kernel_init->init_post->run_init_process->kernel_execve

?

4:init進程在內(nèi)核態(tài)下的分析(也就是kernel_init函數(shù))

4.1:打開控制臺,代碼如下:

1

2

3

4

5

/*?Open?the?/dev/console?on?the?rootfs,?this?should?never?fail?*/

if?(sys_open((const?char?__user?*)?"/dev/console",?O_RDWR,?0)?<?0)

printk(KERN_WARNING?"Warning:?unable?to?open?an?initial?console.\n");

(void)?sys_dup(0);

(void)?sys_dup(0);

? (1)linux系統(tǒng)中每個進程都有自己的一個文件描述符表,表中存儲的是本進程打開的文件。

? (2)linux系統(tǒng)中有一個設(shè)計理念:一切屆是文件。所以設(shè)備也是以文件的方式來訪問的。我們要訪問一個設(shè)備,就要去打開這個設(shè)備對應(yīng)的文件描述符。譬如/dev/fb0這個設(shè)備文件就代表LCD顯示器設(shè)備,/dev/buzzer代表蜂鳴器設(shè)備,/dev/console代表控制臺設(shè)備。打開一個設(shè)備的文件就會得到這個設(shè)備的文件描述符(或者是文件描述符的編號),這個編號就代表這個設(shè)備,以后操作這個設(shè)備就用這個文件描述符來操作它

? (3)這里我們打開了/dev/console文件,并且復(fù)制了2次文件描述符,一共得到了3個文件描述符。這三個文件描述符分別是0、1、2.這三個文件描述符就是所謂的:標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出、標(biāo)準(zhǔn)錯誤。

? (4)進程1打開了三個標(biāo)準(zhǔn)輸出輸出錯誤文件,因此后續(xù)的進程1衍生出來的所有的進程默認都具有這3個三件描述符

?

4.2:掛載根文件系統(tǒng),代碼如下

1

2

3

4

if?(sys_access((const?char?__user?*)?ramdisk_execute_command,?0)?!=?0)?{

ramdisk_execute_command?=?NULL;

prepare_namespace();

}

? (1)prepare_namespace函數(shù)中掛載根文件系統(tǒng)

? (2)根文件系統(tǒng)在哪里?根文件系統(tǒng)的文件系統(tǒng)類型是什么? uboot通過傳參來告訴內(nèi)核這些信息。uboot傳參中的root=/dev/mmcblk0p2 rw 這一句就是告訴內(nèi)核根文件系統(tǒng)在哪里uboot傳參中的rootfstype=ext3這一句就是告訴內(nèi)核rootfs的類型。

? (3)如果內(nèi)核掛載根文件系統(tǒng)成功,則會打印出:VFS: Mounted root (ext3 filesystem) on device 179:2.如果掛載根文件系統(tǒng)失敗,則會打印:No filesystem could mount root, tried: ?yaffs2

? (4)如果內(nèi)核啟動時掛載rootfs失敗,則后面肯定沒法執(zhí)行了。內(nèi)核中設(shè)置了啟動失敗休息5s自動重啟的機制,因此這里會自動重啟,所以有時候大家會看到反復(fù)重啟的情況。

? (5)如果掛載rootfs失敗,可能的原因有:最常見的錯誤就是uboot的bootargs設(shè)置不對。rootfs燒錄失敗(fastboot燒錄不容易出錯,以前是手工燒錄很容易出錯)rootfs本身制作失敗的。(尤其是自己做的rootfs,或者別人給的第一次用)

?

5:執(zhí)行用戶態(tài)下的進程1程序

? (1)上面一旦掛載rootfs成功,則進入rootfs中尋找應(yīng)用程序的init程序,

這個程序就是用戶空間的進程1.找到后用run_init_process(里面的kernel_execve函數(shù))去執(zhí)行他

? (2)我們?nèi)绻_定init程序是誰?方法是:先從uboot傳參cmdline中看有沒有指定,如果有指定先執(zhí)行cmdline中指定的程序。cmdline中的init=/linuxrc這個就是指定rootfs中哪個程序是init程序。這里的指定方式就表示我們rootfs的根目錄下面有個名字叫l(wèi)inuxrc的程序,這個程序就是init程序。如果uboot傳參cmdline中沒有init=xx或者cmdline中指定的這個xx執(zhí)行失敗,還有備用方案。

第一備用:/sbin/init,第二備用:/etc/init,第三備用:/bin/init,第四備用:/bin/sh。

如果以上都不成功,則kernel啟動失敗

總結(jié)

以上是生活随笔為你收集整理的linux内核rest_init分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。