2018-2019-1 20189213《Linux内核原理与分析》第四周作业
《Linux內核原理與分析》第四周學習總結:
1.課本知識總結:
本章內容并不多,首先是介紹了一些Linux內核源代碼的目錄結構,并基于Linux內核源代碼構造一個簡單的操作系統MenuOS,同時在MenuOS啟動過程中跟蹤分析Linux內核的啟動過程。
 操作系統的“兩把寶劍”:中斷上下文、進程上下文。其中中斷上下文的切換主要用來保存現場和恢復現場,而進程上下文實際上是進程執行活動全過程的靜態描述。
 書中所描述的一切內容都是基于Linux內核3.18.6版本,其中Linux內核源碼的目錄包括以下這些:
 其中我們主要關注arch目錄,因為它里面存放了許多CPU體系結構的相關代碼;
 當然也有幾個比較關鍵的目錄:
 block: 存放Linux存儲體系中關于塊設備管理的代碼;
 crypto:存放常見的加密算法的C語言代碼;
 init(初始化):存放Linux內核啟動時的初始化代碼;
 ipc目錄:存放Linux支持的IPC(進程間通信)的代碼實現;
 kernel:存放內核本身需要的一些核心代碼文件;等等。
2.構造一個簡單的Linux內核:
由于實驗是在實驗樓上進行的,已經搭好了環境,所以不再過多進行描述。
 這里主要講如何在自己的虛擬機搭環境,構建一個簡單的Linux內核:
 首先是進行Linux3.18.6內核版本的下載,下載好后編譯并運行,雖然等待時間很長,但自己動手做一遍覺得會有不同的收獲。
 運行后我們可以進行根文件系統的制作,這樣就可以啟動不帶調試信息的Linux內核和MenuOS了:
3.重點實驗:跟蹤分析Linux內核的啟動過程
雖然實驗對照書上內容看操作并不難,但理解起來確實蠻難的。
 第一步:使用gdb跟蹤調試內核,首先命令中有-s與-S參數的加入:
 -S:freeze CPU at startup (use ’c’ to start execution) 在系統啟動的時候凍結CPU,使用c鍵繼續執行后續操作;
 -s:shorthand for -gdb tcp::1234 打開遠程調試端口,默認使用tcp協議1234端口,若不想使用1234端口,則可以使用-gdb tcp:xxxx來取代-s選項 。
 這個指令的作用是在開始的時候就讓CPU停止在啟動的那一刻,我們可以看到如下的界面:
第二步:再打開一個窗口,水平分割,啟動gdb,把內核加載進來,建立連接,并設置相應斷點加用‘c’運行:
第三步:對內核啟動的有關分析:
 (1)start_kernel()
 main.c 中沒有 main 函數,start_kernel() 相當于是C中的main函數。start_kernel是一切的起點,在此函數被調用之前內核代碼是用匯編語言寫的,完成系統的初始化工作,為c代碼的運行設置環境。由調試可得 start_kernel 在500行:
 (2)init_task()
 start_kernel() 函數幾乎涉及到了內核的所有模塊,如:trap_init()(中斷向量的初始化)、mm_init()(內存管理的初始化)sched_init()(調度模塊的初始化)等,首先是510行的init_task():
 可以看出 init_task(0號進程)是 task_struct 類型,是進程描述符,使用宏INIT_TASK對其進行初始化。接下來就是對各種模塊的初始化。
 (3)rest_init()
 通過rest_init()新建kernel_init、kthreadd內核線程:
 在403行代碼中調用 kernel_thread()創建1號內核線程(在 kernel_init 函數正式啟動)。
 這里對比一下init_task 和 kernel_thread():
 kernel_thread()是 fork 出了一個新進程來執行kernel_init 函數,而 init_task 是使用宏進行初始化的。也就是說0進程不是系統通過 kernel_thread 的方式(也就是 fork)創建的(init_task 是唯一一個沒有通過 fork()產生的進程)。
 在405行代碼中調用 kernel_thread()執行 kthreadd函數,創建 PID=2的內核線程:
 kthreadd函數的任務是管理和調度其他內核線程 kernel_thread。for 循環中運行 kthread_create_list 全局鏈表中維護的 kthread, 在create_kthread()函數中,會調用 kernel_thread 來生成一個新的進程并被加入到此鏈表中,因此所有的內核線程都是直接或者間接的以 kthreadd 為父進程。
總結:
 (1)init_task()(PID=0)在創建了init進程后,調用 cpu_idle() 演變成了idle進程,執行一次調度后,init進程運行;
 (2)1號內核線程負責執行內核的部分初始化工作及進行系統配置,最后調用do_execve執行 init 函數,演變成 init 進程(用戶態1號進程),init 進程是內核啟動的第一個用戶級進程;
 (3)kthreadd(PID=2)進程由0號進程創建,始終運行在內核空間, 負責所有內核線程的調度和管理 。
4.個人理解分析及遇到的一些問題:
上述描述的基本都是書上的內容,比較官方也比較難理解。本章內容不多,操作難度也不大,但理解難度很大。
 首先,幾乎所有的內核模塊均會在start_kernel進行初始化。在start_kernel中,會對各項硬件設備進行初始化,包括一些page_address、tick等等,直到最后需要執行的rest_init中,會開始讓系統跑起來。
 那么,rest_init這個過程中,會調用調用kernel_thread來創建內核線程kernel_init,它創建用戶的init進程,初始化內核,并設置成1號進程,這個進程會繼續做相關的系統初始化;
 然后,start_kernel會調用kernel_thread并創建kthreadd,負責管理內核中得所有線程,然后進程ID會被設置為2;
 最后,會創建idle進程(0號進程),不能被調度,并利用循環來不斷調號空閑的CPU時間片,并且從不返回。
問題:
 (1)本章學習中遇到了許多陌生的指令和術語,一邊操作過程中一邊查閱有關資料,但對有些術語還是不太理解。
 (2)在自己虛擬機上搭建環境時,Linux-3.18.6內核版本根據書中鏈接進行下載網速太慢,于是便在Linux官網上進行下載然后解壓運行。
 (3)“gcc -o init linktable.c menu.c test.c -m32 -static –lpthread”執行這句話的時候gcc報錯出現:找不到lpthread?
轉載于:https://www.cnblogs.com/aiYY/p/9892889.html
總結
以上是生活随笔為你收集整理的2018-2019-1 20189213《Linux内核原理与分析》第四周作业的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 机器学习——深度学习之卷积神经网络(CN
- 下一篇: 机器学习——深度学习之编程工具、流行网络
