1. 程式人生 > 實用技巧 >課程學習報告

課程學習報告

目錄

Linux核心基本功能

Linux核心主要由以下幾個功能:程序管理、檔案系統、IO體系結構和裝置驅動程式、記憶體管理等等。

下面對Linux的各個功能進行簡單的介紹。

  1. 程序管理:程序管理是linux核心中最重要的部分,它保證了程式的正常執行。 在Linux中, 程序是系統資源分配的基本單位,也是使用CPU執行的基本排程單位。它實現了對程序的控制和排程。

  2. 檔案系統:在Linux中,一切都是檔案,通過對檔案的定義和操作來控制裝置的執行和資料的儲存。並且使用VFS虛擬檔案系統,實現對多種檔案系統的相容。

  3. IO體系結構和裝置驅動程式:在Linux中,驅動是應用軟體和硬體的橋樑,應用程式只需要呼叫系統軟體的應用程式設計介面,就可以讓相應的硬體完成工作,通過裝置驅動程式的定義和執行實現了對IO裝置操作的控制。

  4. 記憶體管理:記憶體管理子系統可能是linux核心中最為複雜的一個子系統,其支援的功能需求眾多,如頁面對映、頁面分配、頁面回收、頁面交換等,而且對效能也有很高的要求。

1. 程序管理

一個程序的上下文(context)包括程序的狀態、有關變數和資料結構的值、機器暫存器的值和PCB以及有關程式、資料等。

一個程序的執行是在程序的上下文中執行。

當正在執行的程序由於某種原因要讓出處理機時,系統要做程序上下文切換,以使另一個程序得以執行。

當進行上下文切換時系統要首先檢查是否允許做上下文切換(在有些情況下,上下文切換是不允許的,例如系統正在執行某個不允許中斷的原語時)。然後,系統要保留有關被切換程序的足夠資訊,以便以後切換回該程序時,順利恢復該程序的執行。在系統保留了CPU現場之後,排程程式選擇一個新的處於就緒狀態的程序、並裝配該程序的上下文,使CPU的控制權掌握在被選中程序手中。

Linux核心中有關程序的部分資料結構:

struct task_struct {
......
 /* 程序狀態 */
    volatilelongstate;
 /* 指向核心棧 */
    void*stack;
 /* 用於加入程序連結串列 */
structlist_head tasks;
   ......
 /* 指向該程序的記憶體區描述符 */
structmm_struct*mm,*active_mm;
......
 /* 程序ID,每個程序(執行緒)的PID都不同 */
    pid_t pid;
 /* 執行緒組ID,同一個執行緒組擁有相同的pid,與領頭執行緒(該組中第一個輕量級程序)pid一致,儲存在tgid中,執行緒組領頭執行緒的pid和tgid相同 */
    pid_t tgid;
  /* 用於連線到PID、TGID、PGRP、SESSION雜湊表 */
structpid_link pids[PIDTYPE_MAX];
......
  /* 指向建立其的父程序,如果其父程序不存在,則指向init程序 */
    structtask_struct __rcu *real_parent;
  /* 指向當前的父程序,通常與real_parent一致 */
    structtask_struct __rcu *parent;
  /* 子程序連結串列 */
    structlist_head children;
  /* 兄弟程序連結串列 */
    structlist_head sibling;
  /* 執行緒組領頭執行緒指標 */
    structtask_struct*group_leader;
  /* 在程序切換時儲存硬體上下文(硬體上下文一共儲存在2個地方: thread_struct(儲存大部分CPU暫存器值,包括核心態堆疊棧頂地址和IO許可許可權位),核心棧(儲存eax,ebx,ecx,edx等通用暫存器值)) */
    structthread_struct thread;
  /* 當前目錄 */
    structfs_struct*fs;
 /* 指向檔案描述符,該程序所有開啟的檔案會在這裡面的一個指標數組裡 */
structfiles_struct*files;
......
/*訊號描述符,用於跟蹤共享掛起訊號佇列,被屬於同一執行緒組的所有程序共享,也就是同一執行緒組的執行緒此指標指向同一個訊號描述符 */
structsignal_struct*signal;
/*訊號處理函式描述符 */
structsighand_struct*sighand;
......
}

2. 檔案系統

在LINUX系統中有一個重要的概念:一切都是檔案。 其實這是UNIX哲學的一個體現,而Linux是重寫UNIX而來,所以這個概念也就傳承了下來。在UNIX系統中,把一切資源都看作是檔案,包括硬體裝置。UNIX系統把每個硬體都看成是一個檔案,通常稱為裝置檔案,這樣使用者就可以用讀寫檔案的方式實現對硬體的訪問。這樣帶來優勢也是顯而易見的:UNIX 許可權模型也是圍繞檔案的概念來建立的,所以對裝置也就可以同樣處理了。

檔案開啟:

應用程式對open ( )的呼叫將引起核心呼叫服務例程sys_open ( )函式,該函式接收的引數為:要開啟檔案的路徑名和訪問模式等;
該系統呼叫成功後將返回一個檔案描述符,也就是檔案物件指標陣列的一個索引;
系統呼叫不成功時返回-1。

檔案關閉

使用者程式通過close ( )系統呼叫關閉開啟的檔案,該函式接收的引數為要關閉檔案的檔案描述符。
核心服務例程為sys_close ( )函式。

讀檔案流程

程序呼叫庫函式向核心發起讀檔案請求;
核心通過檢查程序的檔案描述符定位到虛擬檔案系統的已開啟檔案列表表項;
呼叫該檔案可用的系統呼叫函式read()。read()函式通過檔案表項鍊接到目錄項模組,根據傳入的檔案路徑,在目錄項模組中檢索,找到該檔案的inode;
在inode中,通過檔案內容偏移量計算出要讀取的頁;
通過inode找到檔案對應的address_space;
在address_space中訪問該檔案的頁快取樹,查詢對應的頁快取結點:
如果頁快取命中,那麼直接返回檔案內容;
如果頁快取缺失,那麼產生一個頁缺失異常,建立一個頁快取頁,同時通過inode找到檔案該頁的磁碟地址,讀取相應的頁填充該快取頁;重新進行第6步查詢頁快取;
檔案內容讀取成功。

虛擬檔案系統

是 Linux 核心中的一個軟體層,用於給使用者空間的程式提供檔案系統介面;
同時,它也提供了核心中的一個抽象功能,允許不同的檔案系統共存。
系統中所有的檔案系統不但依賴 VFS 共存,而且也依靠 VFS 協同工作。
為了能夠支援各種實際檔案系統,VFS 定義了所有檔案系統都支援的基本的、概念上的介面和資料 結構;
同時實際檔案系統也提供 VFS 所期望的抽象介面和資料結構,將自身的諸如檔案、目錄等概念在形式 上與VFS的定義保持一致。一個實際的檔案系統想要被 Linux 支援,就必須提供一個符合VFS標準 的介面,才能與 VFS 協同工作。實際檔案系統在統一的介面和資料結構下隱藏了具體的實現細節,所以在VFS 層和核心的其他部分看來,所有檔案系統都是相同的。

3. 中斷和系統呼叫

為了處理是處理硬體外設I/O,有了中斷機制這個東西。

中斷分外部中斷(硬體中斷)和內部中斷(軟體中斷)。內部中斷⼜稱為異常(Exception),異常⼜分為故障(fault)和陷阱(trap)。中斷(廣義)會改變處理器執行指令的順序,通常與CPU晶片內部或外部硬體電路產生的電訊號相對應。中斷是非同步的:由硬體隨機產生,在程式執行的任何時候可能出現;異常是同步的:在(特殊的或出錯的)指令執行時由CPU控制單元產生。

系統呼叫作為一種特殊的中斷,就是利⽤陷阱(trap)這種軟體中斷⽅式主動從⽤戶態進⼊核心態的。

此時就不得不牽扯到作業系統的“兩把寶劍”程序上下文和中斷上下⽂。

程序上下文是把系統提供給程序的處於動態變化的執行環境總和。

中斷上下文它是一個核心控制路徑,代表了中斷髮生時正在執行的程序執行。

中斷的處理過程:

確定中斷向量。
利用中斷向量在IDT中找到對應中斷門,在中斷門中得到段選擇符從而可以從GDT中找到中斷服務例程的段基址。
確定中斷髮生的特權級合法(linux只有核心態和使用者態兩種特權級,此步用來檢查中斷程式的特權是否低於引起中斷的程式的特權,低優先順序程式不能引起高優先順序程式)
檢查是否發生特權級變化(使用者態陷入核心態,這時候需要設定核心的堆疊),如果發生讀取當前程式的tss段(通過tr暫存器讀取)來選擇新特權級的ss和esp指標,然後儲存舊的ss和esp指標。
若發生的是故障,用引起異常的指令地址修改cs和eip暫存器的值,以使得這條指令在異常處理結束後能被再次執行。
在棧中儲存eflags、cs和eip的內容。
如果異常產生一個硬體出錯碼,則將它儲存在棧中。
裝載cs和eip暫存器,其值分別是IDT表中第i項門描述符的段選擇符和偏移量欄位。這對暫存器值給出中斷或者異常處理程式的第一條指定的邏輯地址。

系統呼叫的過程:

  • 應用程式 程式碼呼叫系統呼叫( xyz ),該函式是一個包裝系統呼叫的 庫函式 ;
  • 庫函式 ( xyz )負責準備向核心傳遞的引數,並觸發 軟中斷 以切換到核心;
  • CPU 被 軟中斷 打斷後,執行 中斷處理函式 ,即 系統呼叫處理函式 ( system_call);
  • 系統呼叫處理函式 呼叫 系統呼叫服務例程 ( sys_xyz ),真正開始處理該系統呼叫

4. 總結

很慚愧,在疫情期間沒有做到自覺得學習,有負孟老師和李老師的付出。實際學習中,對很多概念只能做到巨集觀上理解,很多問題都是不求甚解的狀態,尤其涉及到核心C程式碼,很多沒見過的語法和資料結構讓我很迷糊。我個人使用linux系統已有6年多的時間,因為沒有靜心研究過核心,導致我對linux的認識只浮於表面。所幸今後的實習工作需要用到linux平臺,也算是有了一個補充作業系統知識的契機。此後我將以部落格的形式,對所學所記進行記錄總結。