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

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

更多內容請參考Linux設備驅動程序學習----目錄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設備驅動程序學習----目錄

相關文章
相關標籤/搜索