一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Linux 內(nèi)核中斷內(nèi)幕

 jijo 2008-06-03



本文對中斷系統(tǒng)進(jìn)行了全面的分析與探討,主要包括中斷控制器、中斷分類、中斷親和力、中斷線程化與 SMP 中的中斷遷徙等。首先對中斷工作原理進(jìn)行了簡要分析,接著詳細(xì)探討了中斷親和力的實(shí)現(xiàn)原理,最后對中斷線程化與非線程化中斷之間的實(shí)現(xiàn)機(jī)理進(jìn)行了對比分析。

什么是中斷

Linux 內(nèi)核需要對連接到計(jì)算機(jī)上的所有硬件設(shè)備進(jìn)行管理,毫無疑問這是它的份內(nèi)事。如果要管理這些設(shè)備,首先得和它們互相通信才行,一般有兩種方案可實(shí)現(xiàn)這種功能:

  1. 輪詢(polling 讓內(nèi)核定期對設(shè)備的狀態(tài)進(jìn)行查詢,然后做出相應(yīng)的處理;
  2. 中斷(interrupt 讓硬件在需要的時(shí)候向內(nèi)核發(fā)出信號(變內(nèi)核主動為硬件主動)。

第一種方案會讓內(nèi)核做不少的無用功,因?yàn)檩喸兛倳芷谛缘闹貜?fù)執(zhí)行,大量地耗用 CPU 時(shí)間,因此效率及其低下,所以一般都是采用第二種方案 。 注釋 1

從物理學(xué)的角度看,中斷是一種電信號,由硬件設(shè)備產(chǎn)生,并直接送入中斷控制器(如 8259A)的輸入引腳上,然后再由中斷控制器向處理器發(fā)送相應(yīng)的信號。處理器一經(jīng)檢測到該信號,便中斷自己當(dāng)前正在處理的工作,轉(zhuǎn)而去處理中斷。此后,處理器會通知 OS 已經(jīng)產(chǎn)生中斷。這樣,OS 就可以對這個(gè)中斷進(jìn)行適當(dāng)?shù)奶幚?。不同的設(shè)備對應(yīng)的中斷不同,而每個(gè)中斷都通過一個(gè)唯一的數(shù)字標(biāo)識,這些值通常被稱為中斷請求線。





回頁首


APIC vs 8259A

X86計(jì)算機(jī)的 CPU 為中斷只提供了兩條外接引腳:NMI 和 INTR。其中 NMI 是不可屏蔽中斷,它通常用于電源掉電和物理存儲器奇偶校驗(yàn);INTR是可屏蔽中斷,可以通過設(shè)置中斷屏蔽位來進(jìn)行中斷屏蔽,它主要用于接受外部硬件的中斷信號,這些信號由中斷控制器傳遞給 CPU。

常見的中斷控制器有兩種:

1. 可編程中斷控制器8259A

傳統(tǒng)的 PIC(Programmable Interrupt Controller)是由兩片 8259A 風(fēng)格的外部芯片以“級聯(lián)”的方式連接在一起。每個(gè)芯片可處理多達(dá) 8 個(gè)不同的 IRQ。因?yàn)閺?PIC 的 INT 輸出線連接到主 PIC 的 IRQ2 引腳,所以可用 IRQ 線的個(gè)數(shù)達(dá)到 15 個(gè),如圖 1 所示。


圖 1:8259A 級聯(lián)原理圖
8259A 級聯(lián)原理圖

2. 高級可編程中斷控制器(APIC)

8259A 只適合單 CPU 的情況,為了充分挖掘 SMP 體系結(jié)構(gòu)的并行性,能夠把中斷傳遞給系統(tǒng)中的每個(gè) CPU 至關(guān)重要?;诖死碛桑琁ntel 引入了一種名為 I/O 高級可編程控制器的新組件,來替代老式的 8259A 可編程中斷控制器。該組件包含兩大組成部分:一是“本地 APIC”,主要負(fù)責(zé)傳遞中斷信號到指定的處理器;舉例來說,一臺具有三個(gè)處理器的機(jī)器,則它必須相對的要有三個(gè)本地 APIC。另外一個(gè)重要的部分是 I/O APIC,主要是收集來自 I/O 裝置的 Interrupt 信號且在當(dāng)那些裝置需要中斷時(shí)發(fā)送信號到本地 APIC,系統(tǒng)中最多可擁有 8 個(gè) I/O APIC。

每個(gè)本地 APIC 都有 32 位的寄存器,一個(gè)內(nèi)部時(shí)鐘,一個(gè)本地定時(shí)設(shè)備以及為本地中斷保留的兩條額外的 IRQ 線 LINT0 和 LINT1。所有本地 APIC 都連接到 I/O APIC,形成一個(gè)多級 APIC 系統(tǒng),如圖 2 所示。


圖 2:多級I/O APIC系統(tǒng)
多級I/O APIC系統(tǒng)

目前大部分單處理器系統(tǒng)都包含一個(gè) I/O APIC 芯片,可以通過以下兩種方式來對這種芯片進(jìn)行配置:

1) 作為一種標(biāo)準(zhǔn)的 8259A 工作方式。本地 APIC 被禁止,外部 I/O APIC 連接到 CPU,兩條 LINT0 和 LINT1 分別連接到 INTR 和 NMI 引腳。

2) 作為一種標(biāo)準(zhǔn)外部 I/O APIC。本地 APIC 被激活,且所有的外部中斷都通過 I/O APIC 接收。

辨別一個(gè)系統(tǒng)是否正在使用 I/O APIC,可以在命令行輸入如下命令:

# cat /proc/interrupts
                                    CPU0
                                    0:      90504    IO-APIC-edge  timer
                                    1:        131    IO-APIC-edge  i8042
                                    8:          4    IO-APIC-edge  rtc
                                    9:          0    IO-APIC-level  acpi
                                    12:        111    IO-APIC-edge  i8042
                                    14:       1862    IO-APIC-edge  ide0
                                    15:         28    IO-APIC-edge  ide1
                                    177:          9    IO-APIC-level  eth0
                                    185:          0    IO-APIC-level  via82cxxx
                                    ...
                                    

如果輸出結(jié)果中列出了 IO-APIC,說明您的系統(tǒng)正在使用 APIC。如果看到 XT-PIC,意味著您的系統(tǒng)正在使用 8259A 芯片。





回頁首


中斷分類

中斷可分為同步(synchronous)中斷和異步(asynchronous)中斷:

1. 同步中斷是當(dāng)指令執(zhí)行時(shí)由 CPU 控制單元產(chǎn)生,之所以稱為同步,是因?yàn)橹挥性谝粭l指令執(zhí)行完畢后 CPU 才會發(fā)出中斷,而不是發(fā)生在代碼指令執(zhí)行期間,比如系統(tǒng)調(diào)用。

2. 異步中斷是指由其他硬件設(shè)備依照 CPU 時(shí)鐘信號隨機(jī)產(chǎn)生,即意味著中斷能夠在指令之間發(fā)生,例如鍵盤中斷。

根據(jù) Intel 官方資料,同步中斷稱為異常(exception),異步中斷被稱為中斷(interrupt)。

中斷可分為可屏蔽中斷(Maskable interrupt)和非屏蔽中斷(Nomaskable interrupt)。異??煞譃楣收希?em>fault)、陷阱(trap)、終止(abort)三類。

從廣義上講,中斷可分為四類:中斷故障、陷阱終止。這些類別之間的異同點(diǎn)請參看 表 1。

表 1:中斷類別及其行為
類別 原因 異步/同步 返回行為
中斷 來自I/O設(shè)備的信號 異步 總是返回到下一條指令
陷阱 有意的異常 同步 總是返回到下一條指令
故障 潛在可恢復(fù)的錯(cuò)誤 同步 返回到當(dāng)前指令
終止 不可恢復(fù)的錯(cuò)誤 同步 不會返回

X86 體系結(jié)構(gòu)的每個(gè)中斷都被賦予一個(gè)唯一的編號或者向量(8 位無符號整數(shù))。非屏蔽中斷和異常向量是固定的,而可屏蔽中斷向量可以通過對中斷控制器的編程來改變。





回頁首


Linux 2.6 中斷處理原理簡介

中斷描述符表(Interrupt Descriptor Table,IDT)是一個(gè)系統(tǒng)表,它與每一個(gè)中斷或異常向量相聯(lián)系,每一個(gè)向量在表中存放的是相應(yīng)的中斷或異常處理程序的入口地址。內(nèi)核在允許中斷發(fā)生前,也就是在系統(tǒng)初始化時(shí),必須把 IDT 表的初始化地址裝載到 idtr 寄存器中,初始化表中的每一項(xiàng)。

當(dāng)處于實(shí)模式下時(shí),IDT 被初始化并由 BIOS 程序所使用。然而,一旦 Linux 開始接管,IDT 就被移到 ARM 的另一個(gè)區(qū)域,并進(jìn)行第二次初始化,因?yàn)?Linux 不使用任何 BIOS 程序,而使用自己專門的中斷服務(wù)程序(例程)(interrupt service routine,ISR)。中斷和異常處理程序很像常規(guī)的 C 函數(shù)

有三個(gè)主要的數(shù)據(jù)結(jié)構(gòu)包含了與 IRQ 相關(guān)的所有信息:hw_interrupt_typeirq_desc_tirqaction,圖3 解釋了它們之間是如何關(guān)聯(lián)的。


圖 3:IRQ 結(jié)構(gòu)之間的關(guān)系
IRQ結(jié)構(gòu)之間的關(guān)系

在 X86 系統(tǒng)中,對于 8259A 和 I/O APIC 這兩種不同類型的中斷控制器,hw_interrupt_type 結(jié)構(gòu)體被賦予不同的值,具體區(qū)別參見表 2。

表 2:8259A 和 I/O APIC PIC 的區(qū)別
8259A I/O APIC
static struct hw_interrupt_type i8259A_irq_type = { "XT-PIC", startup_8259A_irq, shutdown_8259A_irq, enable_8259A_irq, disable_8259A_irq, mask_and_ack_8259A, end_8259A_irq, NULL }; static struct hw_interrupt_type ioapic_edge_type = { .typename = "IO-APIC-edge", .startup = startup_edge_ioapic, .shutdown = shutdown_edge_ioapic, .enable = enable_edge_ioapic, .disable = disable_edge_ioapic, .ack = ack_edge_ioapic, .end = end_edge_ioapic, .set_affinity = set_ioapic_affinity, }; static struct hw_interrupt_type ioapic_level_type = { .typename = "IO-APIC-level", .startup = startup_level_ioapic, .shutdown = shutdown_level_ioapic, .enable = enable_level_ioapic, .disable = disable_level_ioapic, .ack = mask_and_ack_level_ioapic, .end = end_level_ioapic, .set_affinity = set_ioapic_affinity, };

在中斷初始化階段,調(diào)用 hw_interrupt_type 類型的變量初始化 irq_desc_t 結(jié)構(gòu)中的 handle 成員。在早期的系統(tǒng)中使用級聯(lián)的8259A,所以將用 i8259A_irq_type 來進(jìn)行初始化,而對于SMP系統(tǒng)來說,要么以 ioapic_edge_type,或以 ioapic_level_type 來初始化 handle 變量。

對于每一個(gè)外設(shè),要么以靜態(tài)(聲明為 static 類型的全局變量)或動態(tài)(調(diào)用 request_irq 函數(shù))的方式向 Linux 內(nèi)核注冊中斷處理程序。不管以何種方式注冊,都會聲明或分配一塊 irqaction 結(jié)構(gòu)(其中 handler 指向中斷服務(wù)程序),然后調(diào)用 setup_irq() 函數(shù),將 irq_desc_tirqaction 聯(lián)系起來。

當(dāng)中斷發(fā)生時(shí),通過中斷描述符表 IDT 獲取中斷服務(wù)程序入口地址,對于 32≤ i ≤255(i≠128) 之間的中斷向量,將會執(zhí)行 push $i-256,jmp common_interrupt 指令。隨之將調(diào)用 do_IRQ() 函數(shù),以中斷向量為 irq_desc[] 結(jié)構(gòu)的下標(biāo),獲取 action 的指針,然后調(diào)用 handler 所指向的中斷服務(wù)程序。

從以上描述,我們不難看出整個(gè)中斷的流程,如圖 4 所示:


圖 4:X86中斷流
X86中斷流

本文作者之一曾經(jīng)對2.6.10的中斷系統(tǒng)進(jìn)行過情景分析,有興趣的讀者可以和作者取得聯(lián)系,獲取相關(guān)資料。





回頁首


中斷綁定——中斷親和力(IRQ Affinity)

在 SMP 體系結(jié)構(gòu)中,我們可以通過調(diào)用系統(tǒng)調(diào)用和一組相關(guān)的宏來設(shè)置 CPU 親和力(CPU affinity),將一個(gè)或多個(gè)進(jìn)程綁定到一個(gè)或多個(gè)處理器上運(yùn)行。中斷在這方面也毫不示弱,也具有相同的特性。中斷親和力是指將一個(gè)或多個(gè)中斷源綁定到特定的 CPU 上運(yùn)行。中斷親和力最初由 Ingo Molnar 設(shè)計(jì)并實(shí)現(xiàn)。

/proc/irq 目錄中,對于已經(jīng)注冊中斷處理程序的硬件設(shè)備,都會在該目錄下存在一個(gè)以該中斷號命名的目錄 IRQ# ,IRQ# 目錄下有一個(gè) smp_affinity 文件(SMP 體系結(jié)構(gòu)才有該文件),它是一個(gè) CPU 的位掩碼,可以用來設(shè)置該中斷的親和力, 默認(rèn)值為 0xffffffff,表明把中斷發(fā)送到所有的 CPU 上去處理。如果中斷控制器不支持 IRQ affinity,不能改變此默認(rèn)值,同時(shí)也不能關(guān)閉所有的 CPU 位掩碼,即不能設(shè)置成 0x0。

我們以網(wǎng)卡(eth1,中斷號 44 )為例,在具有 8 個(gè) CPU 的服務(wù)器上來設(shè)置網(wǎng)卡中斷的親和力(以下數(shù)據(jù)出自內(nèi)核源碼 Documentation\IRQ-affinity.txt):

[root@moon 44]# cat smp_affinity
                                    ffffffff
                                    [root@moon 44]# echo 0f > smp_affinity
                                    [root@moon 44]# cat smp_affinity
                                    0000000f
                                    [root@moon 44]# ping -f h
                                    PING hell (195.4.7.3): 56 data bytes
                                    ...
                                    --- hell ping statistics ---
                                    6029 packets transmitted, 6027 packets received, 0% packet loss
                                    round-trip min/avg/max = 0.1/0.1/0.4 ms
                                    [root@moon 44]# cat /proc/interrupts | grep 44:
                                    44:   0   1785   1785   1783   1783   1   1   0   IO-APIC-level   eth1
                                    [root@moon 44]# echo f0 > smp_affinity
                                    [root@moon 44]# ping -f h
                                    PING hell (195.4.7.3): 56 data bytes
                                    ..
                                    --- hell ping statistics ---
                                    2779 packets transmitted, 2777 packets received, 0% packet loss
                                    round-trip min/avg/max = 0.1/0.5/585.4 ms
                                    [root@moon 44]# cat /proc/interrupts | grep 44:
                                    44:  1068  1785  1785  1784   1784   1069   1070   1069   IO-APIC-level  eth1
                                    [root@moon 44]#
                                    

在上例中,我們首先只允許在 CPU0~3 上處理網(wǎng)卡中斷,接著運(yùn)行 ping 程序,不難發(fā)現(xiàn)在 CPU4~7 上并沒有對網(wǎng)卡中斷進(jìn)行處理。然后只在 CPU4~7 上對網(wǎng)卡中斷進(jìn)行處理, CPU0~3 不對網(wǎng)卡中斷進(jìn)行任何處理,運(yùn)行 ping 程序之后,再次查看 /proc/interrupts 文件時(shí),不難發(fā)現(xiàn) CPU4~7 上的中斷次數(shù)明顯增加,而 CPU0~3 上的中斷次數(shù)沒有太大的變化。

在探討中斷親和力的實(shí)現(xiàn)原理之前,我們首先來了解 I/O APIC 中的組成。

I/O APIC 由一組 24 條 IRQ 線,一張 24 項(xiàng)的中斷重定向表(Interrupt Redirection Table),可編程寄存器,以及通過 APIC 總線發(fā)送和接收 APIC 信息的一個(gè)信息單元組成。其中與中斷親和力息息相關(guān)的是中斷重定向表, 中斷重定向表表中的每一項(xiàng)都可以被單獨(dú)編程以指明中斷向量和優(yōu)先級、目標(biāo)處理器及選擇處理器的方式 。

通過表 2,不難發(fā)現(xiàn) 8259A 和 APIC 中斷控制器最大不同點(diǎn)在于 hw_interrupt_type 類型變量的最后一項(xiàng)。對于 8259A 類型,set_affinity 被置為 NULL,而對于 SMP 的 APIC 類型,set_affinity 被賦值為 set_ioapic_affinity

在系統(tǒng)初始化期間,對于 SMP 體系結(jié)構(gòu),將會調(diào)用 setup_IO_APIC_irqs() 函數(shù)來初始化 I/O APIC 芯片,芯片中的中斷重定向表的 24 項(xiàng)被填充。在系統(tǒng)啟動期間,所有的 CPU 都執(zhí)行 setup_local_APIC() 函數(shù),完成本地的 APIC 初始化。當(dāng)有中斷被觸發(fā)時(shí),將相應(yīng)的中斷重定向表中的值轉(zhuǎn)換成一條消息,然后,通過 APIC 總線把消息發(fā)送給一個(gè)或多個(gè)本地 APIC 單元,這樣,中斷就能立即被傳遞給一個(gè)特定的 CPU,或一組 CPU,或所有的 CPU,從而來實(shí)現(xiàn)中斷親和力。

當(dāng)我們通過 cat 命令將 CPU 掩碼寫進(jìn) smp_affinity 文件時(shí),此時(shí)的調(diào)用路線圖為:write() ->sys_write() ->vfs_write() ->proc_file_write() ->irq_affinity_write_proc() ->set_affinity() ->set_ioapic_affinity() ->set_ioapic_affinity_irq() ->io_apic_write();其中在調(diào)用 set_ioapic_affinity_irq() 函數(shù)時(shí),以中斷號和 CPU 掩碼作為參數(shù),接著繼續(xù)調(diào)用 io_apic_write(),修改相應(yīng)的中斷重定向中的值,來完成中斷親和力的設(shè)置。當(dāng)執(zhí)行 ping 命令時(shí),網(wǎng)卡中斷被觸發(fā),產(chǎn)生了一個(gè)中斷信號,多 APIC 系統(tǒng)根據(jù)中斷重定向表中的值,依照仲裁機(jī)制,選擇 CPU0~3 中的某一個(gè) CPU,并將該信號傳遞給相應(yīng)的本地 APIC,本地 APIC 又中斷它的 CPU,整個(gè)事件不通報(bào)給其他所有的 CPU。





回頁首


新特性展望——中斷線程化(Interrupt Threads)

在嵌入式領(lǐng)域,業(yè)界對 Linux 實(shí)時(shí)性的呼聲越來越高,對中斷進(jìn)行改造勢在必行。在 Linux 中,中斷具有最高的優(yōu)先級。不論在任何時(shí)刻,只要產(chǎn)生中斷事件,內(nèi)核將立即執(zhí)行相應(yīng)的中斷處理程序,等到所有掛起的中斷和軟中斷處理完畢后才能執(zhí)行正常的任務(wù),因此有可能造成實(shí)時(shí)任務(wù)得不到及時(shí)的處理。中斷線程化之后,中斷將作為內(nèi)核線程運(yùn)行而且被賦予不同的實(shí)時(shí)優(yōu)先級,實(shí)時(shí)任務(wù)可以有比中斷線程更高的優(yōu)先級。這樣,具有最高優(yōu)先級的實(shí)時(shí)任務(wù)就能得到優(yōu)先處理,即使在嚴(yán)重負(fù)載下仍有實(shí)時(shí)性保證。

目前較新的 Linux 2.6.17 還不支持中斷線程化。但由 Ingo Molnar 設(shè)計(jì)并實(shí)現(xiàn)的實(shí)時(shí)補(bǔ)丁,實(shí)現(xiàn)了中斷線程化。最新的下載地址為:

http://people./~mingo/realtime-preempt/patch-2.6.17-rt9

下面將對中斷線程化進(jìn)行簡要分析。

在初始化階段,中斷線程化的中斷初始化與常規(guī)中斷初始化大體上相同,在 start_kernel() 函數(shù)中都調(diào)用了 trap_init()init_IRQ() 兩個(gè)函數(shù)來初始化 irq_desc_t 結(jié)構(gòu)體,不同點(diǎn)主要體現(xiàn)在內(nèi)核初始化創(chuàng)建 init 線程時(shí),中斷線程化的中斷在 init() 函數(shù)中還將調(diào)用 init_hardirqs(kernel/irq/manage.c(已經(jīng)打過上文提到的補(bǔ)丁)),來為每一個(gè) IRQ 創(chuàng)建一個(gè)內(nèi)核線程,最高實(shí)時(shí)優(yōu)先級為 50,依次類推直到 25,因此任何 IRQ 線程的最低實(shí)時(shí)優(yōu)先級為 25。

void __init init_hardirqs(void)
                                    {
                                    ……
                                    for (i = 0; i < NR_IRQS; i++) {
                                    irq_desc_t *desc = irq_desc + i;
                                    if (desc->action && !(desc->status & IRQ_NODELAY))
                                    desc->thread = kthread_create(do_irqd, desc, "IRQ %d", irq);
                                    ……
                                    }
                                    }
                                    static int do_irqd(void * __desc)
                                    {
                                    ……
                                    /*
                                    * Scale irq thread priorities from prio 50 to prio 25
                                    */
                                    param.sched_priority = curr_irq_prio;
                                    if (param.sched_priority > 25)
                                    curr_irq_prio = param.sched_priority - 1;
                                    ……
                                    }
                                    

如果某個(gè)中斷號狀態(tài)位中的 IRQ_NODELAY 被置位,那么該中斷不能被線程化。

在中斷處理階段,兩者之間的異同點(diǎn)主要體現(xiàn)在:兩者相同的部分是當(dāng)發(fā)生中斷時(shí),CPU 將調(diào)用 do_IRQ() 函數(shù)來處理相應(yīng)的中斷,do_IRQ() 在做了必要的相關(guān)處理之后調(diào)用 __do_IRQ()。兩者最大的不同點(diǎn)體現(xiàn)在 __do_IRQ() 函數(shù)中,在該函數(shù)中,將判斷該中斷是否已經(jīng)被線程化(如果中斷描述符的狀態(tài)字段不包含 IRQ_NODELAY 標(biāo)志,則說明該中斷被線程化了),對于沒有線程化的中斷,將直接調(diào)用 handle_IRQ_event() 函數(shù)來處理。

fastcall notrace unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs)
                                    {
                                    ……
                                    if (redirect_hardirq(desc))
                                    goto out_no_end;
                                    ……
                                    action_ret = handle_IRQ_event(irq, regs, action);
                                    ……
                                    }
                                    int redirect_hardirq(struct irq_desc *desc)
                                    {
                                    ……
                                    if (!hardirq_preemption || (desc->status & IRQ_NODELAY) || !desc->thread)
                                    return 0;
                                    ……
                                    if (desc->thread && desc->thread->state != TASK_RUNNING)
                                    wake_up_process(desc->thread);
                                    ……
                                    }
                                    

對于已經(jīng)線程化的情況,調(diào)用 wake_up_process() 函數(shù)喚醒中斷處理線程,并開始運(yùn)行,內(nèi)核線程將調(diào)用 do_hardirq() 來處理相應(yīng)的中斷,該函數(shù)將判斷是否有中斷需要被處理,如果有就調(diào)用 handle_IRQ_event() 來處理。handle_IRQ_event() 將直接調(diào)用相應(yīng)的中斷處理函數(shù)來完成中斷處理。

不難看出,不管是線程化還是非線程化的中斷,最終都會執(zhí)行 handle_IRQ_event() 函數(shù)來調(diào)用相應(yīng)的中斷處理函數(shù),只是線程化的中斷處理函數(shù)是在內(nèi)核線程中執(zhí)行的。

并不是所有的中斷都可以被線程化,比如時(shí)鐘中斷,主要用來維護(hù)系統(tǒng)時(shí)間以及定時(shí)器等,其中定時(shí)器是操作系統(tǒng)的脈搏,一旦被線程化,就有可能被掛起,這樣后果將不堪設(shè)想,所以不應(yīng)當(dāng)被線程化。如果某個(gè)中斷需要被實(shí)時(shí)處理,它可以像時(shí)鐘中斷那樣,用 SA_NODELAY 標(biāo)志來聲明自己非線程化,例如:

static struct irqaction irq0 = {
                                    timer_interrupt, SA_INTERRUPT | SA_NODELAY, CPU_MASK_NONE, "timer", NULL, NULL
                                    };
                                    

其中,SA_NODELAYIRQ_NODELAY 之間的轉(zhuǎn)換,是在 setup_irq() 函數(shù)中完成的。





回頁首


中斷負(fù)載均衡—SMP體系結(jié)構(gòu)下的中斷

中斷負(fù)載均衡的實(shí)現(xiàn)主要封裝在 arch\ arch\i386\kernel\io-apic.c 文件中。如果在編譯內(nèi)核時(shí)配置了 CONFIG_IRQBALANCE 選項(xiàng),那么 SMP 體系結(jié)構(gòu)中的中斷負(fù)載均衡將以模塊的形式存在于內(nèi)核中。

late_initcall(balanced_irq_init);
                                    #define late_initcall(fn)		module_init(fn)  //include\linux\init.h
                                    

balanced_irq_init() 函數(shù)中,將創(chuàng)建一個(gè)內(nèi)核線程來負(fù)責(zé)中斷負(fù)載均衡:

static int __init balanced_irq_init(void)
                                    {   ……
                                    printk(KERN_INFO "Starting balanced_irq\n");
                                    if (kernel_thread(balanced_irq, NULL, CLONE_KERNEL) >= 0)
                                    return 0;
                                    else
                                    printk(KERN_ERR "balanced_irq_init: failed to spawn balanced_irq");
                                    ……
                                    }
                                    

balanced_irq() 函數(shù)中,每隔 5HZ=5s 的時(shí)間,將調(diào)用一次 do_irq_balance() 函數(shù),進(jìn)行中斷的遷徙。將重負(fù)載 CPU 上的中斷遷移到較空閑的CPU上進(jìn)行處理。





回頁首


總結(jié)

隨著中斷親和力和中斷線程化的相繼實(shí)現(xiàn),Linux 內(nèi)核在 SMP 和實(shí)時(shí)性能方面的表現(xiàn)越來越讓人滿意,完全有理由相信,在不久的將來,中斷線程化將被合并到基線版本中。本文對中斷線程化的分析只是起一個(gè)拋磚引玉的作用,當(dāng)新特性發(fā)布時(shí),不至于讓人感到迷茫。



參考資料

  1. Rebert Love,《Linux Kernel Development,2rd Edition》,機(jī)械工業(yè)出版社,2006。
  2. Daniel P. Bovet,Marco Cesati,《Understanding the Linux Kernel,3rd Edition》,東南大學(xué)出版社,2006。
  3. Jonatban Corbet 等,魏永明等譯,《Linux設(shè)備驅(qū)動程序》,中國電力出版社,2006。
  4. Gordon Fischer 等,《The Linux Kernel Prime》,機(jī)械工業(yè)出版社,2006。




    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    老熟女露脸一二三四区| 亚洲国产成人久久99精品| 国产又粗又深又猛又爽又黄| 一区二区三区日韩在线| 国产免费无遮挡精品视频| 亚洲国产色婷婷久久精品| 黄片在线免费观看全集| 国产精品夜色一区二区三区不卡| 亚洲专区中文字幕在线| 日本亚洲精品在线观看| 成年男女午夜久久久精品| 日本欧美视频在线观看免费| 婷婷开心五月亚洲综合| 在线中文字幕亚洲欧美一区| 久热这里只有精品九九| 出差被公高潮久久中文字幕| 精品人妻一区二区三区免费| 国产精品午夜视频免费观看| 五月婷婷六月丁香狠狠| 99国产高清不卡视频| 美女激情免费在线观看| 熟女体下毛荫荫黑森林自拍| 久久综合狠狠综合久久综合| 在线视频免费看你懂的| 欧美在线视频一区观看| 东京热男人的天堂社区| 欧美精品久久男人的天堂| 国产午夜精品美女露脸视频| 日本一级特黄大片国产| 五月婷婷六月丁香狠狠| 麻豆欧美精品国产综合久久| 日本一级特黄大片国产| 亚洲国产一级片在线观看| 1024你懂的在线视频| 国产成人精品午夜福利av免费| 午夜视频成人在线观看| 国产内射一级一片内射高清视频| 加勒比东京热拍拍一区二区| 亚洲国产性生活高潮免费视频| 精品国产亚洲av成人一区| 天堂av一区一区一区|