揭陽網(wǎng)站制作建設(shè)免費(fèi)發(fā)布信息的網(wǎng)站平臺
init系統(tǒng)簡介:
Linux 操作系統(tǒng)的啟動(dòng)首先從 BIOS 開始,接下來進(jìn)入 boot loader,由 bootloader 載入內(nèi)核,進(jìn)行內(nèi)核初始化。內(nèi)核初始化的最后一步就是啟動(dòng) pid 為 1 的 init 進(jìn)程,這個(gè)進(jìn)程是系統(tǒng)的第一個(gè)進(jìn)程,它負(fù)責(zé)產(chǎn)生其他所有用戶進(jìn)程。
init 的一些特點(diǎn)
- init是Linux系統(tǒng)操作中不可缺少的程序之一。
- 所謂的init進(jìn)程,它是由內(nèi)核啟動(dòng)的第一個(gè)用戶級進(jìn)程。內(nèi)核自行啟動(dòng)(已被裝入內(nèi)存,開始運(yùn)行,并已初始化所有的設(shè)備驅(qū)動(dòng)程序和數(shù)據(jù)結(jié)構(gòu)等)之后,就通過啟動(dòng)一個(gè)用戶級程序init的方式,完成引導(dǎo)進(jìn)程。所以,init始終是第一個(gè)進(jìn)程(其進(jìn)程編號始終為1)。
- 僅僅將內(nèi)核運(yùn)行起來是毫無實(shí)際用途的,必須由 init 系統(tǒng)將系統(tǒng)代入可操作狀態(tài)。比如啟動(dòng)外殼 shell 后,便有了人機(jī)交互,這樣就可以讓計(jì)算機(jī)執(zhí)行一些預(yù)訂程序完成有實(shí)際意義的任務(wù)(這其實(shí)就是就是后面所說的內(nèi)核態(tài)到用戶態(tài)的轉(zhuǎn)變)。內(nèi)核會(huì)在過去曾使用過init的幾個(gè)地方查找它,它的正確位置(對Linux系統(tǒng)來說)是/sbin/init。如果內(nèi)核找不到init,它就會(huì)試著運(yùn)行/bin/sh,如果運(yùn)行失敗,系統(tǒng)的啟動(dòng)也會(huì)失敗。
Linux下的三個(gè)特殊進(jìn)程
Linux下有三個(gè)特殊的進(jìn)程idle進(jìn)程(PID=0),init進(jìn)程(PID=1),和kthreadd(PID=2)
- idle進(jìn)程由系統(tǒng)自動(dòng)創(chuàng)建,運(yùn)行在內(nèi)核態(tài)。idle進(jìn)程其pid=0,其前身是系統(tǒng)創(chuàng)建的第一個(gè)進(jìn)程,也是唯一一個(gè)沒有通過fork或者kernel_thread產(chǎn)生的進(jìn)程。完成加載系統(tǒng)后,演變?yōu)檫M(jìn)程調(diào)度、交換。
- kthreadd進(jìn)程由idle通過kernel_thread創(chuàng)建,并始終運(yùn)行在內(nèi)核空間,負(fù)責(zé)所有內(nèi)核進(jìn)程的調(diào)度和管理。它的任務(wù)就是管理和調(diào)度其他內(nèi)核線程kernel_thread, 會(huì)循環(huán)執(zhí)行一個(gè)kthread的函數(shù),該函數(shù)的作用就是運(yùn)行kthread_create_list全局鏈表中維護(hù)的kthread, 當(dāng)我們調(diào)用kernel_thread創(chuàng)建的內(nèi)核線程會(huì)被加入到此鏈表中,因此所有的內(nèi)核線程都是直接或者間接的以kthreadd為父進(jìn)程 。
- init進(jìn)程由idle通過kernel_thread創(chuàng)建,在內(nèi)核空間完成初始化后,加載init程序。在這里我們就主要了解下init進(jìn)程,init進(jìn)程由0進(jìn)程創(chuàng)建,完成系統(tǒng)的初始化,是系統(tǒng)中所有其他用戶進(jìn)程的祖先進(jìn)程
Linux中的所有進(jìn)程都是由init進(jìn)程創(chuàng)建并運(yùn)行的。首先Linux內(nèi)核啟動(dòng),然后在用戶空間中啟動(dòng)init進(jìn)程,再啟動(dòng)其他系統(tǒng)進(jìn)程。在系統(tǒng)啟動(dòng)完成后,init將變成為守護(hù)進(jìn)程監(jiān)視系統(tǒng)其他進(jìn)程。(內(nèi)核態(tài)轉(zhuǎn)變?yōu)橛脩魬B(tài))
大致過程為:0號進(jìn)程->1號內(nèi)核進(jìn)程->1號用戶進(jìn)程(init進(jìn)程)->getty進(jìn)程->shell進(jìn)程
init進(jìn)程完成從內(nèi)核態(tài)向用戶態(tài)的轉(zhuǎn)變
一個(gè)進(jìn)程先后兩種狀態(tài)
init進(jìn)程剛開始運(yùn)行的時(shí)候是內(nèi)核態(tài),它屬于一個(gè)內(nèi)核線程,然后運(yùn)行一個(gè)用戶態(tài)下面的程序后(如/sbin/init),把自己轉(zhuǎn)成用戶態(tài)(后面的進(jìn)程需要工作在用戶態(tài)下)。
init進(jìn)程完成了從內(nèi)核態(tài)到用戶態(tài)的過渡,因此后續(xù)的其他進(jìn)程都可以工作在用戶態(tài)。
init進(jìn)程在內(nèi)核態(tài)下的工作內(nèi)容
主要是掛載根文件系統(tǒng),并試圖找到用戶態(tài)下的那個(gè)init程序。(這句話看出,init進(jìn)程是早于init程序運(yùn)行的。)
init進(jìn)程要把自己轉(zhuǎn)成用戶態(tài)就必須運(yùn)行一個(gè)用戶態(tài)的應(yīng)用程序,要運(yùn)行這個(gè)應(yīng)用程序就必須得找到這個(gè)應(yīng)用程序,要找到這個(gè)應(yīng)用程序就必須得掛載根文件系統(tǒng),因?yàn)樗械膽?yīng)用程序都在文件系統(tǒng)中。
內(nèi)核源代碼中的所有函數(shù)都處于內(nèi)核態(tài),執(zhí)行其中任何一個(gè)都不能脫離內(nèi)核態(tài)。而應(yīng)用程序必須不屬于內(nèi)核源代碼,這樣才能保證應(yīng)用程序處于用戶態(tài)。這里執(zhí)行的init程序和內(nèi)核不在一起,由根文件系統(tǒng)另外提供。
init進(jìn)程在用戶態(tài)下的工作內(nèi)容
init進(jìn)程大部分有意義的工作都是在用戶態(tài)下進(jìn)行的。init進(jìn)程對操作系統(tǒng)的意義在于,其他所有的用戶進(jìn)程都直接或者間接派生自init進(jìn)程。
init進(jìn)程如何從內(nèi)核態(tài)跳躍到用戶態(tài) ?還能回來不?
init進(jìn)程處于內(nèi)核態(tài)時(shí),通過函數(shù)do_execve來執(zhí)行一個(gè)用戶空間編譯鏈接的應(yīng)用程序就跳躍到用戶態(tài)了。
- 跳躍過程中進(jìn)程號沒有改變,一直是進(jìn)程1。
- 跳躍過程是單向的,一旦執(zhí)行init程序轉(zhuǎn)到用戶態(tài),整個(gè)操作系統(tǒng)就算真正運(yùn)轉(zhuǎn)起來了,以后只能在用戶態(tài)下工作,用戶態(tài)下想要進(jìn)入內(nèi)核態(tài)只能通過調(diào)用API。
1、init進(jìn)程掛載了根文件系統(tǒng)
(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)掛載結(jié)果
如果內(nèi)核掛載根文件系統(tǒng)成功,則會(huì)打印出:VFS: Mounted root (ext3 filesystem) on device 179:2。(也可能其他數(shù)字)
如果掛載根文件系統(tǒng)失敗,則會(huì)打印:No filesystem could mount root, tried: yaffs2
(4)如果內(nèi)核啟動(dòng)時(shí)掛載rootfs失敗,則后面無法執(zhí)行。
內(nèi)核中設(shè)置了啟動(dòng)失敗休息5s自動(dòng)重啟的機(jī)制,因此這里會(huì)自動(dòng)重啟,所以有時(shí)候大家會(huì)看到反復(fù)重啟的情況。
(5)如果掛載rootfs失敗,可能的原因有
最常見的錯(cuò)誤就是uboot的bootargs設(shè)置不對。
rootfs燒錄失敗(fastboot燒錄不容易出錯(cuò))。
rootfs本身制作失敗的。
2、init進(jìn)程執(zhí)行init程序完成內(nèi)核態(tài)到用戶態(tài)的轉(zhuǎn)變
(1)一旦掛載rootfs成功,則進(jìn)入rootfs中尋找應(yīng)用程序的init程序(在init_post()函數(shù)中),找到后用run_init_process去執(zhí)行。
(2)如果確定init程序是誰?
先從uboot傳參cmdline中看有沒有指定,如果有指定先執(zhí)行cmdline中指定的程序。比如init=/linuxrc表示rootfs的根目錄下的linuxrc程序就是init程序。
如果uboot傳參cmdline中沒有init=xx或者cmdline中指定的這個(gè)xx執(zhí)行失敗,還有備用方案。第一備用:/sbin/init,第二備用:/etc/init,第三備用:/bin/init,第四備用:/bin/sh。如果以上都不成功,則沒有辦法了。
init=/linuxrc一般指向busybox。
3、init進(jìn)程構(gòu)建了用戶交互界面
(1)init進(jìn)程是其他用戶進(jìn)程的祖先。
linux系統(tǒng)中一個(gè)進(jìn)程的創(chuàng)建是通過其父進(jìn)程創(chuàng)建出來的。根據(jù)這個(gè)理論只要有一個(gè)父進(jìn)程就能生出一堆子孫進(jìn)程了。
(2)init啟動(dòng)了login進(jìn)程(用戶登錄進(jìn)程)、命令行進(jìn)程(提供命令行環(huán)境)、shell進(jìn)程(提供命令解釋和執(zhí)行)。
(3)shell進(jìn)程啟動(dòng)了其他用戶進(jìn)程。
命令行和shell一旦工作,用戶就可以在命令行下通過./xx的方式來執(zhí)行其他應(yīng)用程序,每一個(gè)應(yīng)用程序的運(yùn)行就是一個(gè)進(jìn)程。
4、init進(jìn)程打開了控制臺
(1)linux系統(tǒng)中每個(gè)進(jìn)程都有自己的一個(gè)文件描述符表,表中存儲(chǔ)的是本進(jìn)程打開的文件。
(2)linux系統(tǒng)中一切皆是文件,因此設(shè)備也是以文件的方式來訪問的。要訪問一個(gè)設(shè)備,就要打開此設(shè)備對應(yīng)的文件描述符。譬如/dev/fb0這個(gè)設(shè)備文件就代表LCD顯示器設(shè)備,/dev/buzzer代表蜂鳴器設(shè)備,/dev/console代表控制臺設(shè)備。
(3)這里打開了/dev/console文件,并且復(fù)制了2次文件描述符,一共得到了3個(gè)文件描述符。這三個(gè)文件描述符分別是0、1、2,就是所謂的標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出、標(biāo)準(zhǔn)錯(cuò)誤這3個(gè)文件描述符。
(4)進(jìn)程1打開了這3個(gè)文件描述符,因此進(jìn)程1衍生出來的所有的進(jìn)程默認(rèn)都具有這3個(gè)文件描述符。
運(yùn)行級別
簡單的說,運(yùn)行級就是操作系統(tǒng)當(dāng)前正在運(yùn)行的功能級別。這個(gè)級別有多種,以centos為例,6和7版本的設(shè)置方法不同,具體對應(yīng)關(guān)系如下。
init level (centos 6 /etc/inittab) | systemctl target(centos 7) | 說明 |
---|---|---|
0 | poweroff.target | 停機(jī)(千萬不能把initdefault 設(shè)置為0 ) |
1 | rescure.target | 單用戶(救援)模式 |
2 | multi-user.target | 多用戶,沒有 NFS |
3 | multi-user.target | 完整的多用戶文本模式級別,登錄后進(jìn)入到控制臺命令行模式 |
4 | 未使用 | |
5 | graphical.target | X11 (xwindow,能夠正常切換的前提是系統(tǒng)支持) |
6 | reboot.target | 重新啟動(dòng) |
[root@k8s-m1 ~]# ll /usr/lib/systemd/system/runlevel*target
lrwxrwxrwx 1 root root 15 Feb 27 16:14 /usr/lib/systemd/system/runlevel0.target -> poweroff.target
lrwxrwxrwx 1 root root 13 Feb 27 16:14 /usr/lib/systemd/system/runlevel1.target -> rescue.target
lrwxrwxrwx 1 root root 17 Feb 27 16:14 /usr/lib/systemd/system/runlevel2.target -> multi-user.target
lrwxrwxrwx 1 root root 17 Feb 27 16:14 /usr/lib/systemd/system/runlevel3.target -> multi-user.target
lrwxrwxrwx 1 root root 17 Feb 27 16:14 /usr/lib/systemd/system/runlevel4.target -> multi-user.target
lrwxrwxrwx 1 root root 16 Feb 27 16:14 /usr/lib/systemd/system/runlevel5.target -> graphical.target
lrwxrwxrwx 1 root root 13 Feb 27 16:14 /usr/lib/systemd/system/runlevel6.target -> reboot.target
運(yùn)行級別的配置
centos6設(shè)置默認(rèn)的啟動(dòng)級別
# 查看運(yùn)行級別: centos7 也可以使用該命令。[root@k8s-m1 ~]# runlevel N 3
# 修改運(yùn)行級別:臨時(shí)修改: init level(對應(yīng)的級別即可)永久修改:需要修改 /etc/inittab 文件。
在最下面的一行中的語句 id:5:initdefault 中的數(shù)字5改成需要的啟動(dòng)程度就可以了,一般是命令行模式 3
centos7設(shè)置默認(rèn)的啟動(dòng)級別
#centos7修改設(shè)置默認(rèn)的系統(tǒng)級別
[root@k8s-m1 ~]# systemctl set-default multi-user.target
Removed symlink /etc/systemd/system/default.target.
Created symlink from /etc/systemd/system/default.target to /usr/lib/systemd/system/multi-user.target.
#centos7查看默認(rèn)的系統(tǒng)級別
[root@k8s-m1 ~]# systemctl get-default multi-user.target
參考:https://blog.csdn.net/m0_45406092/article/details/130660743
更多關(guān)于Linux的知識請前往博客主頁查看。