1. 程式人生 > >2018-2019-1 20189206 《Linux內核原理與分析》第四周作業

2018-2019-1 20189206 《Linux內核原理與分析》第四周作業

存儲 中斷機制 部分 獨立 color article struct 用戶空間 存取

linux內核分析學習筆記 ——第三章 MenuOS的構造


計算機的“三大法寶”和操作系統的“兩把寶劍”

三大法寶

  • 程序存儲計算機 即馮諾依曼體系結構,基本上是所有計算機的基礎性的邏輯框架
  • 函數調用堆棧 高級語言可以運行的起點就是函數調用堆棧
  • 中斷機制

  • 中斷上下文 保存現場和恢復現場
  • 進程上下文 進程的調度

構建一個linux內核--MenuOS系統

linux內核源碼幾個重要的目錄

  • arch目錄
    • 是與體系結構相關的子目錄列表,存放了許多CPU體系結構相關的代碼
    • 該目錄主要作用是使linux內核支持不同的CPU體系結構
  • init目錄
    • 存放linux內核啟動時的初始化代碼
    • init
      目錄下有main.c源文件,是整個linux內核啟動的開始
  • kernel目錄
    • 存放內核本身所需要的一些核心代碼文件
    • 存放進程調度相關的代碼
  • lib目錄
    • 公用庫文件
    • 在內核編程中不能使用C語言的標準庫函數,lib目錄就是用來替代那些標準庫函數的

構造MenuOS系統

MenuOS系統由Linux內核鏡像和根文件系統集成起來的

技術分享圖片

上圖所示,在實驗樓linux環境下,利用圖示命令啟動MenuOS系統。
  • qemu仿真kernel
  • bzImage是壓縮的內核映像
  • 根文件系統一般包括內存根文件系統和磁盤根文件系統
    • 本系統中利用rootf.img只有一個init功能,用menu程序代替init。

技術分享圖片

相關概念

  • 文件系統和根文件系統
    • 文件系統:是對一個存儲設備上的數據和元數據進行組織的機制,有利於用戶和操作系統之間的交互。文件系統的用戶只要知道所需文件的文件名,就可存取文件中的信息,而無需知道這些文件究竟存放在什麽地方。
    • 根文件系統:也是一種文件系統,並且它是內核啟動時,所掛載的第一個文件系統,內核代碼的映像文件保存在根文件系統中,系統引導啟動程序會在根文件系統掛載之後從中把一些初始化腳本和服務加載到內存中去運行。

文件系統和內核是完全獨立的兩個部分,linux啟動第一個必須掛載根文件系統

  • 內核編譯之後會生成兩個文件,一個是Image,另一個是zImage,其中Image為內核映像文件,zImage為內核的一種映像壓縮文件。其中bzImage適用於大內核,zImage適用於小內核。

跟蹤調試linux內核的啟動過程

使用gdb跟蹤調試內核,使用兩個參數,-s 和-S
- -s 是在1234端口上創建了一個gdb-server
- -S 是在CPU初始化之前凍結起來
技術分享圖片

利用target remote:1234建立連接,在start_kernel處建立斷點,輸入c繼續執行,將會看到,系統開始啟動執行,到start_kernel處停止。
技術分享圖片

再設置一個斷點rest_init繼續執行,停在斷點處
技術分享圖片

linux內核啟動過程分析

  • start_kernal()函數
    在位於init目錄下的main.c文件中,有內核啟動的起點函數start_kernal()在此函數調用之前,代碼主要工作是完成硬件的初始化等。
    技術分享圖片

    • 圖中可以看到init_task是一個struct task_struct類型的變量。是進程描述符,使用宏INIT_TASK直接對其進行初始化。
    • task_struct就是內核線程,init_task就是0號進程,是系統創建的第一個進程,也是唯一一個沒有通過fork或者kernel_thread產生的進程,最後演變成idel進程
  • rest_init()函數
    技術分享圖片

    • kernel_thread()函數作用是創建新的內核線程,除了0號進程,其余所有的內核線程都是由kernel_thread()這個接口產生的。下圖所示是kernel_thread()的源代碼。
      技術分享圖片

    • kthreadd()函數的任務是管理和調度其他內核線程,可以看到在kthreadd()代碼中,有一個while(1)循環執行,將進的內核線程加入到kthread_creat_list全局鏈表中。也就是當調用kernel_thread()創建的內核線程會被加入到鏈表中
      技術分享圖片

針對於rest_init()函數來說,會啟動三個進程,分別是idle(0號進程)、kernel_init(1號進程)、kthreadd(2號進程)

idle(0號進程) 由init_task進程創建後,調用cpu_idle()演變而成,

kernel_init(1號進程)由idle進程調用kernel_thread()創建,在內核空間完成初始化後, 演變成init程序,init進程是內核啟動的第一個用戶態進程。<font color="Tomato">kernel_init運行在內核空間,隨後會完成從內核態向用戶態的轉變,變成init進程,運行在用戶空間</font>在系統啟動完成完成後,init將變為**守護進程**監視系統其他進程。

kthreadd(2號進程)由idle通過kernel_thread創建,並始終運行在內核空間, 負責所有內核線程的調度和管理,也是大部分創建的內核進程的父進程。

下圖所示,是linux內核啟動的流程示意圖:
技術分享圖片

參考資料:
內核啟動階段進程分析

Linux內核線程的總結與思考

Linux下1號進程的前世(kernel_init)今生(init進程)----Linux進程的管理與調度(六)

問題

線程與進程

在分析linux內核啟動過程中,設計到了好幾個進程的啟動與轉變,書上的描述方式是 內核線程 但是創建的又是進程,我就分不清楚內核線程和進程的關系,我就去找了些概念:

  • 進程:指在系統中能夠獨立運行並作為資源分配的基本單位,進程只能由父進程建立。
  • 線程:是進程中的一個實體,作為系統調度的基本單位
    • 進程的個體是完全獨立的,而線程間是彼此依存的。
    • 多進程環境中,任何一個進程的終止,不會影響到其他進程。而多線程環境中,父線程終止,全部子線程被迫終止(沒有了資源)。而任何一個子線程終止一般不會影響其他線程,除非子線程執行了exit()系統調用。任何一個子線程執行exit(),全部線程同時滅亡。

可以看出,進程和線程是包含的關系,對於書上內核線程的描述就更加迷惑了,又查找了關於linux系統下的進程與線程相關資料:

  • 內核線程,只是一個稱呼,實際上就是一個進程,有自己獨立的TCB,參與內核調度,也參與內核搶占。這個進程的特別之處有兩點,第一、該進程沒有前臺。第二、永遠在內核態中運行。
  • 內核線程類似於用戶進程,通常用於並並發處理性質的任務,並且可以搶占調度。不同於用戶進程,內核線程位於內核空間,並且可以訪問內核函數和內核數據。

2018-2019-1 20189206 《Linux內核原理與分析》第四周作業