Linux設備驅動程序學習----2.內核模塊與應用程序的對比


內核模塊與應用程序的對比

更多內容請參考Linux設備驅動程序學習----目錄

1. 內核模塊與應用程序的對比

內核模塊和應用程序之間的不同之處:

  1. 大多數中小規模的應用程序是從頭到尾執行單個任務,而模塊卻只是預先注冊自己以便服務於將來的某個請求,然后初始化函數立即結束。即模塊初始化函數(hello_init)的任務就是為以后調用模塊函數預先做准備。模塊的退出函數(hello_exit)將在模塊被卸載之前調用。

  2. 這和事件驅動編程有點類似,但不是所有的應用程序都是事件驅動的,而每個內核模塊都是這樣的。事件驅動程序和內核模塊之間的另一個區別是,應用程序在退出時,可以不管資源的釋放或者其他的清除工作,但模塊的退出函數必須撤銷初始化函數所做的一切,保證沒有多余內容殘留在系統中。

  3. 應用程序可以調用它並未定義的函數,因為鏈接過程能夠解析外部引用,從而鏈接使用適當的函數庫。而模塊僅僅被鏈接到內核,因此模塊能調用的函數僅僅是由內核導出的那些函數,而不存在任何可鏈接的函數庫。因為沒有任何函數庫會和模塊鏈接,因此源文件中不能包含通常應用程序的頭文件。內核模塊只能使用作為內核一部分的函數。和內核相關的大多數相關頭文件保存在include/linux和include/asm目錄中。

  4. 應用程序和內核編程的處理錯誤的方式不同,應用程序的段錯誤可以使用調試器跟蹤到源代碼中的問題,而內核錯誤即使不影響系統,也會殺死當前進程。

模塊卸載的好處,有助於縮短模塊化驅動程序的開發周期。

2. 用戶空間和內核空間

  模塊運行在內核空間,應用程序運行在用戶空間。

  在Unix中,內核運行在最高級別,即超級用戶態,這個級別可以進行所有的操作。而應用程序運行在最低級別,即用戶態,這個級別處理器控制着對硬件的直接訪問及對內存的非授權訪問。

  內核空間和用戶空間,不僅說明兩種模式具有不同的優先級等級,還說明每個模式都有自己的內存映射,即自己的地址空間。

  當應用程序執行系統調用或者被硬件中斷掛起時,Unix將執行模式從用戶空間切換到內核空間。執行系統調用的內核代碼運行在進程上下文中,代表調用進程執行操作。因此能夠訪問進程地址空間的所有數據。而處理器硬件中斷的內核代碼和進程時異步的,和任何一個進程無關。

  模塊化代碼在內核空間運行,用於擴展內核功能。驅動程序要執行兩類任務,模塊中的某些函數作為系統調用的一部分執行;其他函數則負責中斷處理。

3. 內核中的並發

  內核編程和應用程序編程的區別在於對並發的處理。大部分應用程序,除了多線程應用程序外,通常都是順序執行的。內核代碼的運行環境更加復雜,即使是最簡單的內核模塊,都需要注意:同一時刻,可能會有很多事情發生。

內核編程必須考慮並發問題的原因:

  1. Linux系統中通常正在運行多個並發進程,並且可能有多個進程同時使用驅動程序;
  2. 大多數設備能夠中斷處理器,而中斷處理程序異步運行,而且可能在驅動程序正試圖處理其他任務時被調用;
  3. 有些軟件抽象(如:內核定時器)也是異步運行的;
  4. Linux可能運行在對稱多處理器系統(SMP),因此可能同時不止一個CPU運行驅動程序;
  5. Linux2.6內核代碼已經是可搶占的,即使在單處理器系統上也存在類似多處理器系統的並發問題。

  Linux內核代碼(包括驅動程序)必須是可重入的,必須能夠同時運行在多個上下文中。內核數據結構要保證多個線程分開執行,訪問共享數據的代碼必須避免破壞共享數據。驅動要能夠處理並發問題,同時避免競態。內核代碼不能假定在給定代碼段中能夠獨占處理器。

4. 當前進程

  雖然內核模塊不像應用程序那樣順序地執行,然而內核執行的大多數操作還是和某個特定進程相關。內核代碼可通過訪問全局項current來獲得當前進程。

  current在<asm/current.h>中定義,是一個指向struct task_struct的指針。current指針指向當前正在運行的進程。可以通過訪問struct task_struct的某些成員來打印當前進程的進程ID和命令名:

printk(KERN_INFO "The process is \"%s\" (pid %i)\n", 
        current->comm, current->pid);

  存儲在current->comm成員中的命令名是當前進程所執行的程序文件的基本名稱,裁剪在15個字符以內。

5. 其他細節

  應用程序在虛擬內存中布局,並具有一塊很大的棧空間。棧用來保存函數調用歷史及當前活動函數中的自動變量。而內核具有很小的棧,可能只有一個4096字節大小的頁空間。驅動的函數必須和整個內核空間調用鏈一同共享這個棧。因此,不能聲明大的自動變量,如果需要大的結構,應該在調用時動態分配該結構。

  在內核API中,具有雙下划線(__)的函數名稱,通常是接口的底層組件,應謹慎使用。

  內核代碼不能實現浮點數運算,內核代碼中不需要浮點運算。

更多內容請參考Linux設備驅動程序學習----目錄


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM