linux中斷執行緒化

2021-05-25 00:46:58 字數 4719 閱讀 6782

引用**:

linux的中斷執行緒化實現

linux 核心中斷內幕

中斷執行緒化

介紹(interrupt threads)

在嵌入式領域,業界對 linux 

實時性的呼聲越來越高,對中斷進行改造勢在必行。在 

linux 

中,中斷具有最高的優先順序。不論在任何時刻,只要產生中斷事件,核心將立即執行相應的中斷處理程式,等到所有掛起的中斷和軟中斷處理完畢後才能執行正常的任務,因此有可能造成實時任務得不到及時的處理。中斷執行緒化之後,中斷將作為核心執行緒執行而且被賦予不同的實時優先順序,實時任務可以有比中斷執行緒更高的優先順序。這樣,具有最高優先順序的實時任務就能得到優先處理,即使在嚴重負載下仍有實時性保證。

目前較新的 linux 2.6.17 

還不支援中斷執行緒化。但由 

ingo molnar 

下面將對中斷執行緒化進行簡要分析。

在初始化階段,中斷執行緒化的中斷初始化與常規中斷初始化大體上相同,在 

start_kernel() 函式中都呼叫了 

trap_init() 

和 init_irq() 

兩個函式來初始化 

irq_desc_t 

結構體,

不同點主要體現在核心初始

化建立 init 

執行緒時,

中斷執行緒化的中斷在 init() 

函式中還將呼叫 

init_hardirqs

(kernel/irq/manage.c

(已經打過上文提到的補丁)),

來為每乙個 irq 

建立乙個核心執行緒

,最高實時優先順序為 50

,依次類推直到 

25,因此任何 

irq 

執行緒的最低實時優先順序為 25。

void __init init_hardirqs(void) }

static int do_irqd(void * __desc)

如果某個中斷號狀態位中的 

irq_nodelay

被置位,那麼該中斷不能被執行緒化。

在中斷處理階段,兩者之間的異同點主要體現在:兩者相同的部分是當發生中斷時,cpu 

將呼叫 

do_irq() 

函式來處理相應的中斷,

do_irq() 

在做了必要的相關處理之後呼叫 

__do_irq()

。兩者最大的不同點體現在 __do_irq() 

函式中,在該函式中,將判斷該中斷是否已經被執行緒化(

如果中斷描述符的狀態字段不包含 irq_nodelay 

標誌,則說明該中斷被執行緒化了

),對於沒有執行緒化的中斷,將直接呼叫 

handle_irq_event()

函式來處理。

fastcall notrace unsigned int __do_irq(unsigned int irq, struct pt_regs *regs)

int redirect_hardirq(struct irq_desc *desc)

對於已經執行緒化的情況,呼叫

wake_up_process() 函式喚醒中斷處理執行緒

,並開始執行,

核心執行緒將呼叫 do_hardirq() 

來處理相應的中斷

,該函式將判斷是否有中斷需要被處理,如果有就呼叫 handle_irq_event() 

來處理。

handle_irq_event() 

將直接呼叫相應的中斷處理函式來完成中斷處理。

不難看出,不管是執行緒化還是非執行緒化的中斷,最終都會執行 handle_irq_event() 

函式來呼叫相應的中斷處理函式,

只是執行緒化的中斷處理函式是在核心執行緒中執行的。

並不是所有的中斷都可以被執行緒化,比如時鐘中斷

,主要用來維護系統時間以及定時器等,其中定時器是作業系統的脈搏,一旦被執行緒化,就有可能被掛起,這樣後果將不堪設想,所以不應當被執行緒化。

如果某個中斷需要被實時處理,它可以像時鐘中斷那樣,用 sa_nodelay 

標誌來宣告自己非執行緒化

,例如:

static struct irqaction irq0 = ;

其中,sa_nodelay 

到 irq_nodelay 

之間的轉換,是在 

setup_irq() 

函式中完成的。

linux的中斷執行緒化實現

2.6.25.8核心實現了中斷執行緒化,核心為每乙個中斷向量建立了乙個中斷執行緒,具體就是在

結構irq_desc

中增加了乙個

task_struct

來代表這個執行緒:

struct irq_desc 

在 中斷產生的時候,還是和往常一樣進入do_irq,

這個函式幾乎沒有什麼變化,在

do_irq

中呼叫了

irq_desc

的handle_irq

函式,這個 

handle_irq

是向量相關的,比如有邊緣觸發等等,這個方式涉及到了硬體規程,故不深入討論,實際上,每個匯流排邦定到乙個中斷向量,而匯流排的中斷方式是匯流排相關的所以中斷向量的方式也就和硬體相關了,這裡就以

level type

為例來說明,

level type

的handle_irq

是handle_level_irq:

void handle_level_irq(unsigned int irq, struct irq_desc *desc)

我們看看每個中斷向量的中斷執行緒是怎麼初始化的,初始化的細節可以帶給我們一大部分必要的資訊,在實際開發中一定注意這一點,乙個好的初始化帶來的是將來操作的方便與清晰:

void __init 

init_hardirqs

(void)

}static int start_irq_thread(int irq, struct irq_desc *desc)

smp_mb();

wake_up_process(desc->thread); //一切就緒之前即

desc->thread

被賦值之前可能已經有了中斷,故喚醒該中斷執行緒處理之。

return 0; }

static int do_irqd(void * __desc) ;

struct irq_desc *desc = __desc;

current->flags |= pf_nofreeze | pf_hardirq;

param.sched_priority = max_user_rt_prio/2;

sys_sched_setscheduler(current->pid, sched_fifo, ¶

m); //

設定實時優先順序

while (!kthread_should_stop())  while (current->state == task_running);

local_irq_enable_nort();

schedule(); 

//一輪處理完畢後切換到別的程序,實際上除了實時程序可能搶占中斷執行緒,中斷執行緒被強佔的可能性極小,因此要主動切出。 }

__set_current_state(task_running);

return 0; }

static void do_hardirq(struct irq_desc *desc)

最終在thread_xx_irq

中呼叫handle_irq_event

來實際處理中斷請求

。當該中斷向量上沒有中斷要處理的時候,對應的中斷執行緒就主動切出了,而中斷來臨的時候redirect_hardirq

會wakeup

對應向量上的中斷執行緒。 

現在我們來看看linux

中斷執行緒化的意義,傳統的

linux

核心上,中斷都是作為最高優先順序的執行緒存在的,它實際上並沒有什麼軟體優先順序的概念,而是 硬體架構決定了硬體中斷到來的時候在該中斷沒有被遮蔽的條件下必須處理,即便是

linux

中最高優先順序的實時程序也要向中斷讓路,這就大大削弱了 

linux

的實時效能,乙個實時任務正在執行,將一直被中斷打斷,特別是在網路負載大的時候,雖然

linux

將耗時的操作都置於軟中斷,但是畢竟哪怕很小 延時的硬體中斷也要延時,多個小的延時積累起來可能會有很大的延時,這不是實時操作所希望的,於是就有了一種想法,

能否讓中斷也參與到優先順序排隊,於是中斷執行緒化就是必然結果了

。可是即便大操作放到了執行緒中,但是畢竟像common_interrupt

和do_irq

linux

的這種中斷執行緒化實現僅僅將實時任務被硬體打斷的延時降低到了很低的程度,實時任務被中斷打斷本身並沒有得到改善,改善這個境地的乙個方案就是引入

硬體中斷優先順序並和執行緒優先順序聯絡

,在處理實時任務時非使能遮蔽掉不相關的任何硬體中斷,使它們不再發生,就像solaris

那樣,當然這可以利用硬體的特性,引入「

cpu當前優先順序」的概念,當

cpu處於優先順序

p時,任何低於

p的中斷都不能發生,

cpu當前優先順序和執行緒優先順序以及中 斷優先順序直接關聯,關於這個方案的實現可以參考

windows

的irql

或者solaris

的ipl。

強制中斷執行緒化threadirqs

kernel 提供了乙個命令列引數threadirqs,這個引數會讓irq 中斷強制執行在thread context,這個時候不管使用者是否 static int init setup forced irqthreads char arg early param threadirqs setup ...

中斷執行緒 interrupt

呼叫interrupt 通知執行緒應該中斷 1 如果執行緒處於阻塞狀態,則執行緒立即退出被阻塞狀態,並丟擲乙個interruptedexception異常 2 如果執行緒處於正常活動狀態,那 package com.mall.controllor.alene import sun.managemen...

中斷執行緒的方式

變數標識 匿名內部類使用區域性變數時,必須是 final,否則編譯報錯 匿名內部類使用字段,不需要 final 使用 volatile 修飾,實現多執行緒間變數的可見性 volatile boolean loop true while condition test public void testw...