理解Linux中斷 (3)

2021-06-05 12:56:32 字數 3338 閱讀 2009

4、下半部

在中斷處理過程中,不能睡眠。另外,它執行的時候,會把當前中斷線在所有處理器上都遮蔽(在ack中完成遮蔽);更糟糕的情況是,如果乙個處理程式是sa_interrupt型別,它執行的時候會禁上所有本地中斷(通過cli指令完成),所以,中斷處理應該盡可能快的完成。所以linux把中斷處理分為上半部和下半部。

上半部由中斷處理程式完成,它通常完成一些和硬體相關的操作,比如對中斷的到達的確認。有時它還會從硬體拷貝資料,這些工作對時間非常敏感,只能靠中斷處理程式自己完成。而把其它工作放到下半部實現。

下半部的執行不需要乙個確切的時間,它會在稍後系統不太繁忙時執行。下半部執行的關鍵在於執行的時候允許響應所有的中斷。最早,linux用」bottom half」實現下半部,這種機制簡稱bh,但是即使屬於不同的處理器,也不允許任何兩個bottom half同時執行,這種機制簡單,但是卻有效能瓶頸。不久,又引入任務佇列(task queue)機制來實現下半部,但該機制仍不夠靈活,沒法代替整個bh介面。

從2.3開始,核心引入軟中斷(softirqs)和tasklet,並完全取代了bh。2.5中,bh最終捨去,在2.6中,核心用有三種機制實現下半部:軟中斷,tasklet和工作佇列。tasklet是基於軟中斷實現的。

軟中斷可以在多個cpu上同時執行,即使它們是同一型別的,所以,軟中斷處理程式必須是可重入的,或者顯示的用自旋鎖保護相應的資料結構。而相同的tasklet不能同時在多個cpu上執行,所以tasklet不必是可重入的;但是,不同型別的tasklet可以在多個cpu上同時執行。一般來說,tasklet比較常用,它可以處理絕大部分的問題;而軟中斷用得比較少,但是對於時間要求較高的地方,比如網路子系統,常用軟中斷處理下半部工作。

4.1、軟中斷

核心2.6中定義了6種軟中斷:

下標越低,優先順序越高。

4.1.1、資料結構

(1)軟中斷向量

//linux/interrupt.h

struct softirq_action

;//kernel/softirq.c

//軟中斷向量陣列

static struct softirq_action softirq_vec[32] __cacheline_aligned_in_smp;

核心定義了乙個包含32個軟中斷向量的陣列,所以最多可有32個軟中斷,實際上,核心目前只使用了6個軟中斷。

(2)    preempt_count欄位

位於任務描述符的preempt_count是用來跟蹤核心搶占和核心控制路徑巢狀關鍵資料。其各個位的含義如下:

位            描述

0——7    preemption counter,核心搶占計數器(最大值255)

8——15   softirq counter,軟中斷計數器(最大值255)

16——27  hardirq counter,硬體中斷計數器(最大值4096)

28        preempt_active標誌

第乙個計數用來表示核心搶占被關閉的次數,0表示可以搶占。第二個計數器表示推遲函式(下半部)被關閉的次數,0表示推遲函式開啟。第三個計數器表示本地cpu中斷巢狀的層數,irq_enter()增加該值,irq_exit減該值。

巨集in_interrupt()檢查current_thread_info->preempt_count的hardirq和softirq來斷定是否處於中斷上下文。如果這兩個計數器之一為正,則返回非零。

(3) 軟中斷控制/狀態結構

softirq_vec是個全域性量,系統中每個cpu所看到的是同乙個陣列。但是,每個cpu各有其自己的「軟中斷控制/狀態」結構,這些資料結構形成乙個以cpu編號為下標的陣列irq_stat(定義在include/asm-i386/hardirq.h中)

typedef struct  ____cacheline_aligned irq_cpustat_t;

//位於kernel/softirq.c

irq_cpustat_t irq_stat[nr_cpus] ____cacheline_aligned;

4.1.2、軟中斷初始化

可以通過open_softirq註冊軟中斷處理程式:

//位於kernel/softirq.c

//nr:軟中斷的索引號

// softirq_action:處理函式

//data:傳遞給處理函式的引數值

void open_softirq(int nr, void (*action)(struct softirq_action*), void *data)

//軟中斷初始化

void __init softirq_init(void)

軟中斷執行時,允許響應中斷,但它自己不能睡眠,4.1.3、觸發軟中斷raise_softirq會將軟中斷設定為掛起狀態,並在下一次執行do_softirq中投入執行。

//位於kernel/softirq.c

void fastcall raise_softirq(unsigned int nr)

inline fastcall void raise_softirq_irqoff(unsigned int nr)

h++;

pending >>= 1;

} while (pending);

//關閉中斷

local_irq_disable();

//再一次檢查軟中斷位圖,因為在執行軟中斷處理函式時,新的軟中斷可能產生.

pending = local_softirq_pending();

if (pending && --max_restart)

goto restart;

/*如果還有多的軟中斷沒有處理,通過wakeup_softirqd喚醒核心執行緒處理本地cpu餘下的軟中斷.

*/if (pending)

wakeup_softirqd();

//減softirq counter的值

__local_bh_enable();

}(3)軟中斷執行點

核心會週期性的檢查是否有掛起的軟中斷,它們位於核心**的以下幾個點:

(1)核心呼叫local_bh_enable()函式開啟本地cpu的軟中斷:

//位於kernel/softirq.c

void local_bh_enable(void)

理解中斷 3

4 下半部 在中斷處理過程中,不能睡眠。另外,它執行的時候,會把當前中斷線在所有處理器上都遮蔽 在ack中完成遮蔽 更糟糕的情況是,如果乙個處理程式是sa interrupt型別,它執行的時候會禁上所有本地中斷 通過cli指令完成 所以,中斷處理應該盡可能快的完成。所以linux把中斷處理分為上半部...

linux 中斷理解

1 程序 執行緒只針對的是應用層,而核心呼叫 驅動沒有這種概念,呼叫的都是核心呼叫裡相同的函式或變數,所以應用層多個應用操作同個硬體時,特別是要加互斥操作,8250通過cs針腳決定傳送資料給哪個串列埠 2 傳送 接收的解決併發操作,主要防止重複呼叫該函式,等待函式的硬體還沒操作完才允許再呼叫,接收一...

Linux 怎麼理解Linux軟中斷?

為了解決中斷處理程式執行過長和中斷丟失的問題,linux 將中斷處理過程分成了兩個階段,也就是上半部和下半部 舉個最常見的網絡卡接收資料報的例子,讓你更好地理解。網絡卡接收到資料報後,會通過硬體中斷的方式,通知核心有新的資料到了。這時,核心就應該呼叫中斷處理程式來響應它。你可以自己先想一下,這種情況...