📖 推薦閱讀:《Yocto項目實戰教程:高效定制嵌入式Linux系統》
🎥 更多學習視頻請關注 B 站:嵌入式Jerry
Linux內核驅動開發核心問題全解
本文系統梳理了 Linux 驅動開發、內核同步、中斷處理、內存管理、進程通信、系統啟動等典型場景中的高頻核心問題,涵蓋中斷上下文與進程上下文、下半部機制、鎖與內存分配、網絡通信、init 啟動流程等內容,配以關鍵代碼片段,適合工程實踐參考。
一、中斷與驅動開發
1. 中斷上下文與進程上下文的區別
- 中斷上下文:由CPU響應外設信號進入,沒有進程調度能力,不能休眠(不能 sleep / schedule),用于處理緊急、耗時短的操作。
- 進程上下文:運行在內核線程或用戶進程中,可以主動調度和休眠,適合處理復雜或耗時任務。
2. 中斷下半部機制(tasklet、softirq、workqueue)
- tasklet/softirq:在中斷返回后、軟中斷上下文中調度執行,不能睡眠。
- workqueue:由內核線程執行,可休眠,適合需要阻塞或耗時的操作。
示例:tasklet 調度下半部
void tasklet_handler(unsigned long data) {// 執行實際下半部工作
}
DECLARE_TASKLET(my_tasklet, tasklet_handler, 0);
irqreturn_t my_irq_handler(int irq, void *dev_id) {tasklet_schedule(&my_tasklet); // 調度下半部return IRQ_HANDLED;
}
3. request_irq 注冊格式及參數
int request_irq(unsigned int irq, irq_handler_t handler,unsigned long flags, const char *name, void *dev);
irq
:中斷號handler
:中斷服務函數,簽名為irqreturn_t func(int, void*)
flags
:如IRQF_SHARED
name
:用于/proc/interrupts
dev
:設備標識
4. 中斷處理流程
- 硬件觸發中斷
- 匯編入口 (
arch/x86/entry/entry_64.S
等) - 通用分發 (
kernel/irq/handle.c
) - 調用驅動注冊的 handler
- 調度下半部(如 tasklet、napi、workqueue)
二、同步、鎖與多核并發
5. 多核系統緩存一致性與內存屏障
- 多核緩存一致性:依賴硬件協議(如 MESI),軟件無需手動刷新緩存。
- 內存屏障(如
mb()
):用于保證CPU/編譯器的內存操作順序,防止亂序。
代碼示例:內存屏障
#include <asm/barrier.h>
void sync_example(void) {a = 1;mb(); // 確保a的寫操作對其他核可見b = 2;
}
6. 進程間共享內存同步與死鎖防范
- 共享內存不是線程安全,需加鎖同步
- 推薦
pthread_mutex_t
,需PTHREAD_PROCESS_SHARED
屬性 - 死鎖風險:如進程異常退出未解鎖,可用健壯互斥鎖
PTHREAD_MUTEX_ROBUST
代碼片段:進程間共享互斥鎖
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(&shared->lock, &attr);
// 使用時加鎖/解鎖
pthread_mutex_lock(&shared->lock); // 臨界區
pthread_mutex_unlock(&shared->lock);
7. 自旋鎖與互斥鎖適用場景
- 自旋鎖:適合內核臨界區/中斷上下文,不能睡眠
- 互斥鎖:適合進程/線程上下文,允許休眠
三、內存管理機制
8. kmalloc 與 vmalloc 的區別
對比項 | kmalloc | vmalloc |
---|---|---|
連續性 | 物理+虛擬連續 | 虛擬連續物理不連續 |
分配效率 | 快 | 慢 |
適用場景 | 小塊/需DMA | 大塊/無需DMA |
分配器 | slab+buddy | 伙伴分配多個物理頁 |
9. slab 與 buddy 分配器
- slab:管理常用小對象緩存(如 kmalloc-32、kmalloc-64)
- buddy:以頁為單位(2^n),用于大塊內存,支持拆分/合并
10. kmalloc(32) 和 kmalloc(4096) 行為差異
- kmalloc(32):分配小對象,來自 slab 緩存池(如 kmalloc-32),實際為一頁切片
- kmalloc(4096):直接分配整頁,調用 buddy 分配器
偽代碼邏輯:
kmalloc(size)-> slab 分配(若 size 小于頁)-> buddy 分配(若 size 大于等于頁)
11. malloc、頁表與物理內存關系
- 應用層 malloc 在用戶空間分配虛擬地址,由 glibc 切塊
- 真正物理內存分配由內核通過頁表管理,內存頁來自 buddy 分配器
四、進程通信與網絡
12. 進程間通信方式
- 管道(pipe, fifo)
- 消息隊列
- 共享內存(shmget/shmat)
- 信號量
- 本地/網絡 socket
- 信號、文件鎖等
13. TCP 與 UDP 的區別
對比項 | TCP(SOCK_STREAM) | UDP(SOCK_DGRAM) |
---|---|---|
是否連接 | 有連接 | 無連接 |
可靠性 | 可靠,順序保證 | 不可靠,可能丟包 |
速度 | 慢 | 快 |
用途 | Web、SSH、文件傳輸 | DNS、直播、語音 |
14. socket() 返回值
- 成功:返回文件描述符(>=0),不論 TCP 還是 UDP
- 失敗:返回 -1,需查 errno
- 0/1/2 通常是標準輸入/輸出/錯誤
代碼示例
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) perror("socket error");
五、系統啟動與 init 流程
15. init 進程的作用及根文件系統掛載
- 內核掛載根文件系統(/)并啟動 init 進程(如 /sbin/init, systemd, busybox init)
- init 進程負責掛載 /proc、/sys、/dev 等虛擬文件系統,啟動系統服務
真實內核片段:init 進程啟動
// init/main.c (Linux 內核)
static const char * const init_paths[] = {"/sbin/init", "/etc/init", "/bin/init", "/bin/sh", NULL };
for (p = init_paths; *p; p++)if (!run_init_process(*p)) return 0;
結語
本文梳理了 Linux 驅動開發、同步機制、內存管理、通信協議、系統啟動等多個核心環節及其典型代碼實現,為深入理解與實踐 Linux 內核提供參考。建議結合源碼實際查閱、動手實驗和知識串聯,形成體系化認知。
📖 推薦閱讀:《Yocto項目實戰教程:高效定制嵌入式Linux系統》
🎥 更多學習視頻請關注 B 站:嵌入式Jerry