20169207《Linux内核原理与分析》第五周作业
這周的任務主要分為兩個方面,第一方面,學習MOOC網上視頻第三講并完成配套的實驗。第二方面,學習課本的第四章和第六章。
首先從實驗開始講起,前期我們對Linux內核的源碼做了一個簡單的了解。包括Main函數是Linux內核運行的起點,具體是Start_kernel,就相當與C語言的Main函數。還介紹了一些和安全,網絡,聲音,腳本,和工具相關的包。包括介紹了一些Linux的歷史和發展。
接下來啟動內核進入menu程序。
接下來要使用gdb跟蹤調試內核.
vmlinux 它是是未壓縮的內核,即編譯出來的最原始的文件
用于kernel調試,產生system.map符號表,不能用于直接加載,
bzImage 壓縮的內核映像
initrd 是在系統引導過程中掛載的一個臨時根文件系統
這里的S是用來凍結cpu運行的,
s是用來指定端口的,若不想使用1234端口,則可以使用-gdb tcp:xxxx來取代-s選項。
這里需要再打開一個shell窗口,開始使用gdb跟蹤調試內核。
(gdb) file linux-3.18.6/vmlinux #在gdb界面中targe remote之前加載符號表,打開gdb需要調試得文件。
將帶有調試信息得linux鏡像加載進來。
(gdb) target remote:1234#建立gdb和gdbserver之間的連接,按c 讓qemu上的linux繼續進行。
鏈接到我們剛才啟動得凍結得linux系統。
(gdb)break start_kernel#斷點的設置可以在target remote之前,也可以在之后。
按c之后開始啟動內核。按n單步執行。s進入函數,finish結束掉當前函數。
list命令顯示當前的代碼。break可跳到自己需要觀察的代碼段!然后逐步的觀察運行情況。
內核掛接根文件系統成功以后,將通過run_init_process()函數執行應用程序。這是一個嘗試的過程,如果execute_command存在,則執行execute_command;如果不存在,則順序執行/sbin/init、/etc/init、/bin/init、/bin/sh,直到有一個執行成功為止。如果都不存在,則會調用panic()上報錯誤。下面是kernel_init()函數:
static int __ref kernel_init(void *unused)
{
int ret; kernel_init_freeable();/* need to finish all async __init code before freeing the memory */async_synchronize_full();free_initmem();mark_rodata_ro();system_state = SYSTEM_RUNNING;numa_default_policy();flush_delayed_fput();if (ramdisk_execute_command) {ret = run_init_process(ramdisk_execute_command);if (!ret)return 0;pr_err("Failed to execute %s (error %d)\n",ramdisk_execute_command, ret);}/** We try each of these until one succeeds.** The Bourne shell can be used instead of init if we are* trying to recover a really broken machine.*/if (execute_command) {ret = run_init_process(execute_command);if (!ret)return 0;pr_err("Failed to execute %s (error %d). Attempting defaults...\n",execute_command, ret);}if (!try_to_run_init_process("/sbin/init") ||!try_to_run_init_process("/etc/init") ||!try_to_run_init_process("/bin/init") ||!try_to_run_init_process("/bin/sh"))return 0;panic("No working init found. Try passing init= option to kernel. ""See Linux Documentation/init.txt for guidance.");
}
start_kernel()函數負責初始化內核各子系統,最后調用 rest_init(),啟動一個叫作init的內核線程,繼續初始化。在 init 內核線程中實現的功能很多,最重要的是負責完成掛接根文件系統、初始化設備驅動和啟動用戶空間的init進程等重要工作。
閱讀課本的第四章和第六章。首先,在進程調度章節,結合本科期間操作系統的進程調度,對搶占式和非搶占式多任務,進程調度算法以及實現,搶占和上下文切換,實時調度策略這些概念有了全新的認識。
進程調度程序是確保進程能有效工作的一個內核子系統。
多任務操作系統就是能同時并發地交互執行多個進程的操作系統,期可以劃分為兩類:非搶占式多任務和搶占式多任務。Linux采用的是搶占式多任務。
進程分為I/O消耗型和處理器消耗型,調度策略通常要做到進程響應迅速和最大系統利用率。Linux更傾向于優先調度I/O消耗性進程。
Linux的進程優先級采用兩種不同的優先級范圍。第一種是用nice值,范圍是從-20到+19,默認為0,nice值越高優先級越低;第二種是實時優先級,其值可配置,默認范圍是從0到99,數值越大優先級越高,而且任何實時進程優先級都搞與普通進程。
Linux進程調度算法為CFS“完全公平調度算法(CFS)”,它是一個針對普通進程的調度類,算法實現定義在文件kernel/sched_fair.c中。Linux中并未直接分配時間片到進程,而是將處理器的使用比劃分給了進程。CFS下每個進程獲得的時間片的底線稱為最小粒度,默認是1ms。
進程調度主要入口點是schedule(),在進程進行搶占和上下文切換時候都要調用它來完成的。搶占分為用戶搶占和內核搶占。用戶搶占發生在內核即將返回用戶空間的時候即內核從系統調用返回用戶空間或者從中斷處理程序返回用戶空間時,如果內核從檢查到need_resched標志被設置,就會調用schedule()選擇一個更適合的進程投入運行。Linux完整的支持內核搶占,即只要重新調度是安全的(沒有持有鎖),內核就可以在任何時間搶占正在執行的任務,內核搶占一般發生在中斷處理程序正在執行且返回內核空間之前、內核代碼在一次具有可搶占性的時候、內核中的任務顯式調用了schedule()或者內核中的任務阻塞。
在內核數據結構章節,介紹了鏈表,隊列,映射,二叉樹等結構。然后在講了他們在linux內核中的具體實現。這些知識點在本科期間的或多或少的涉及過一部分。結合本科期間的知識和現在的新資料,讓我對計算機的內部結構和運行方式又加深了了解。數據結構我們之前都學過,本課講的主要有鏈表、隊列、映射和二叉樹。我們都已經十分熟悉,只是在Linux下會有些許不同。
Linux內核中鏈表實現獨樹一幟,它不是將數據結構塞入鏈表,而是將鏈表節點塞入數據結構。簡單來說,Linux內核是將prev和next兩個指針封裝成為一個list_head的結構體并塞入父結構結點,其中prev和next兩個指針分別指向相鄰結點的list_head結構體,通過宏container_of()從鏈表指針找到父結構中包含的任何變量
struct list_head{
struct list list_head next;
struct list list_head prev;
}
struct fox{
unsigned long tail_length;
unsigned long weight;
bool is_fantastic;
struct list_head list;
}
容易看出鏈接起來的只是fox結構中的子結構list_head。
紅黑樹是一種自平衡二叉搜索樹,具有特殊著色屬性,或紅或黑,有下面六個屬性:
?所有節點要么著紅色,要么著黑色;
?葉子節點都是黑色;
?葉子節點不包含數據;
?所有非葉子節點都有兩個子節點;
?如果一個節點是紅色,則它的子節點都是黑色;
?在一個節點到其葉子節點的路徑中,如果總是包含同樣數目的黑色節點,則該路徑相比其他路徑是最短的。
轉載于:https://www.cnblogs.com/littletang/p/5990767.html
總結
以上是生活随笔為你收集整理的20169207《Linux内核原理与分析》第五周作业的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【JAVA并发编程实战】1、对象的共享
- 下一篇: linux 设置中文版man手册