作業系統核心

上半部與下半部(延後的中斷工作)

當一個裝置打斷 CPU 時,核心面對一個兩難:在它處理那次中斷期間,其他中斷(與一般工作)都被擱置,所以處理常式必須快如閃電——然而為了回應而需做的工作(處理一個網路封包、複製磁碟資料)可能相當可觀。經典的解法是把回應切成兩半:上半部是微小、緊急、在中斷被停用的情況下立刻執行的部分,而下半部是較重的後續工作,被延後到稍晚、可以安全地多花一點時間時才執行。

分工如下。上半部(真正的中斷處理常式)做最低限度的事:向裝置應答好讓它停止舉起中斷、抓取任何時間關鍵的資料、記下還有工作要做、排程下半部,然後盡快返回。下半部接著在稍後執行,做大量的處理。Linux 提供幾種下半部機制,主要差別在於它們是否可以睡眠:softirq 是一組固定的、高效能、不可睡眠的延後常式;tasklet 是給驅動用的、以 softirq 為基礎的較簡單機制,同樣不可睡眠;而 workqueue 在一個核心執行緒裡、以行程上下文執行你的延後函式,這意味著它「可以」睡眠(阻塞、配置可能等待的記憶體、取得互斥鎖)。

為何根本要有這個切分:把一切都放在上半部做,會讓中斷停用得太久,傷害整個系統的回應性——一個慢吞吞的網路處理常式可能拖延計時器、磁碟、一切。把重的部分延後,能讓緊急路徑保持短促。要內化的關鍵規則是那個睡眠的區別:softirq 與 tasklet 跑在中斷上下文,絕不可睡眠;而 workqueue 跑在行程上下文,可以睡眠。選錯機制——試圖在 softirq 裡睡眠——是一個經典的核心臭蟲,會讓機器死結或當機。

網卡 IRQ 觸發 -> 上半部:向卡應答、暫存封包指標、排程一個 softirq、返回(中斷重新啟用)。稍後 -> 下半部(softirq):走過 TCP/IP 堆疊、交付給通訊端。需要睡眠?改用 workqueue。

上半部微小、現在就跑;下半部稍後做粗活。只有 workqueue(行程上下文)可以睡眠。

最重要的單一規則:softirq 與 tasklet 跑在中斷上下文,不可睡眠;而 workqueue 跑在行程上下文,可以睡眠。試圖在 softirq 裡睡眠、阻塞或取得會睡眠的互斥鎖,是嚴重的臭蟲——依你的工作是否會阻塞來選擇下半部機制。

又稱
interrupt handler top/bottom halfsoftirq / tasklet / workqueuedeferred work上半部/下半部