4.6.7 中斷描述符表
中斷描述符表(Interrupt Descriptor Table,IDT)將每個(gè)異常或中斷向量分別與它們的處理過(guò)程聯(lián)系起來(lái)。與GDT和LDT表類似,IDT也是由8字節(jié)長(zhǎng)描述符組成的一個(gè)數(shù)組。與GDT 不同的是,表中第1項(xiàng)可以包含描述符。為了構(gòu)成IDT表中的一個(gè)索引值,處理器把異常或中斷的向量號(hào)乘以8。因?yàn)樽疃嘀挥?56個(gè)中斷或異常向量,所以 IDT無(wú)需包含多于256個(gè)描述符。IDT中可以含有少于256個(gè)描述符,因?yàn)橹挥锌赡馨l(fā)生的異常或中斷才需要描述符。不過(guò)IDT中所有空描述符項(xiàng)應(yīng)該設(shè)置其存在位(標(biāo)志)為0。
IDT表可以駐留在線性地址空間的任何地方,處理器使用IDTR寄存器來(lái)定位IDT表的位置。這個(gè)寄存器中含有IDT表32位的基地址和16位的長(zhǎng)度(限長(zhǎng))值,如圖4-26所示。IDT表基地址應(yīng)該對(duì)齊在8字節(jié)邊界上以提高處理器的訪問(wèn)效率。限長(zhǎng)值是以字節(jié)為單位的IDT表的長(zhǎng)度。
?圖4-26 中斷描述符表IDT和寄存器IDTR
LIDT和SIDT指令分別用于加載和保存IDTR寄存器的內(nèi)容。LIDT指令用于把內(nèi)存中的限長(zhǎng)值和基地址操作數(shù)加載到IDTR寄存器中。該指令僅能由當(dāng)前特權(quán)級(jí)CPL是0的代碼執(zhí)行,通常被用于創(chuàng)建IDT時(shí)的操作系統(tǒng)初始化代碼中。SIDT指令用于把IDTR中的基地址和限長(zhǎng)內(nèi)容復(fù)制到內(nèi)存中。該指令可在任何特權(quán)級(jí)上執(zhí)行。
如果中斷或異常向量引用的描述符超過(guò)了IDT的界限,處理器會(huì)產(chǎn)生一個(gè)一般保護(hù)性異常。
4.6.8 IDT描述符
IDT表中可以存放3種類型的門描述符:中斷門(Interrupt gate)描述符、陷阱門(Trap gate)描述符、任務(wù)門(Task gate)描述符。
圖4-27給出了這三種門描述符的格式。中斷門和陷阱門含有一個(gè)長(zhǎng)指針(即段選擇符和偏移值),處理器使用這個(gè)長(zhǎng)指針把程序執(zhí)行權(quán)轉(zhuǎn)移到代碼段中異常或中斷的處理過(guò)程中。這兩個(gè)段的主要區(qū)別在于處理器操作EFLAGS寄存器IF標(biāo)志上。IDT中任務(wù)門描述符的格式與GDT和LDT中任務(wù)門的格式相同。任務(wù)門描述符中含有一個(gè)任務(wù)TSS段的選擇符,該任務(wù)用于處理異常或中斷。
?圖4-27 中斷門、陷阱門和任務(wù)門描述符格式
4.6.9 異常與中斷處理
處理器對(duì)異常和中斷處理過(guò)程的調(diào)用操作方法與使用CALL指令調(diào)用程序過(guò)程和任務(wù)的方法類似。當(dāng)響應(yīng)一個(gè)異常或中斷時(shí),處理器使用異常或中斷的向量作為IDT表中的索引。如果索引值指向中斷門或陷阱門,則處理器使用與CALL指令操作調(diào)用門類似的方法調(diào)用異常或中斷處理過(guò)程。如果索引值指向任務(wù)門,則處理器使用與CALL指令操作任務(wù)門類似的方法進(jìn)行任務(wù)切換,執(zhí)行異常或中斷的處理任務(wù)。
異常或中斷門引用運(yùn)行在當(dāng)前任務(wù)上下文中的異常或中斷處理過(guò)程,如圖4-28所示。門中的段選擇符指向GDT或當(dāng)前LDT中的可執(zhí)行代碼段描述符。門描述符中的偏移字段指向異常或中斷處理過(guò)程的開(kāi)始處。
?(點(diǎn)擊查看大圖)圖4-28 中斷過(guò)程調(diào)用
當(dāng)處理器執(zhí)行異常或中斷處理過(guò)程調(diào)用時(shí)會(huì)進(jìn)行以下操作:
(1)如果處理過(guò)程將在高特權(quán)級(jí)(如0級(jí))上執(zhí)行時(shí)就會(huì)發(fā)生堆棧切換操作。堆棧切換過(guò)程如下:
處理器從當(dāng)前執(zhí)行任務(wù)的TSS段中得到中斷或異常處理過(guò)程使用的堆棧的段選擇符和棧指針(例如tss.ss0、tss.esp0)。然后處理器會(huì)把被中斷程序(或任務(wù))的棧選擇符和棧指針壓入新棧中,如圖4-29所示。
?圖4-29 轉(zhuǎn)移到中斷處理過(guò)程時(shí)堆棧的使用方法
接著處理器會(huì)把EFLAGS、CS和EIP寄存器的當(dāng)前值也壓入新棧中。
如果異常會(huì)產(chǎn)生一個(gè)錯(cuò)誤號(hào),那么該錯(cuò)誤號(hào)也會(huì)被最后壓入新棧中。
(2)如果處理過(guò)程將在被中斷任務(wù)同一個(gè)特權(quán)級(jí)上運(yùn)行,那么:
處理器把EFLAGS、CS和EIP寄存器的當(dāng)前值保存在當(dāng)前堆棧上。
如果異常會(huì)產(chǎn)生一個(gè)錯(cuò)誤號(hào),那么該錯(cuò)誤號(hào)也會(huì)被最后壓入新棧中。
為了從中斷處理過(guò)程中返回,處理過(guò)程必須使用IRET指令。IRET指令與RET指令類似,但I(xiàn)RET還會(huì)把保存的寄存器內(nèi)容恢復(fù)到EFLAGS 中。不過(guò)只有當(dāng)CPL是0時(shí)才會(huì)恢復(fù)EFLAGS中的IOPL字段,并且只有當(dāng)CPL不大于IOPL時(shí),IF標(biāo)志才會(huì)被改變。 如果當(dāng)調(diào)用中斷處理過(guò)程時(shí)發(fā)生了堆棧切換,那么在返回時(shí)IRET指令會(huì)切換到原來(lái)的堆棧。
(1)異常和中斷處理過(guò)程的保護(hù)
異常和中斷處理過(guò)程的特權(quán)級(jí)保護(hù)機(jī)制與通過(guò)調(diào)用門調(diào)用普通過(guò)程類似。處理器不允許把控制轉(zhuǎn)移到比CPL更低特權(quán)級(jí)代碼段的中斷處理過(guò)程中,否則將產(chǎn)生一個(gè)一般保護(hù)性異常。另外,中斷和異常的保護(hù)機(jī)制在以下方面與一般調(diào)用門過(guò)程不同:
因?yàn)橹袛嗪彤惓O蛄繘](méi)有RPL,因此在隱式調(diào)用異常和中斷處理過(guò)程時(shí)不會(huì)檢查RPL。
只有當(dāng)一個(gè)異常或中斷是由INT n、INT 3或INT 0指令產(chǎn)生時(shí),處理器才會(huì)檢查中斷或陷阱門中的DPL。此時(shí)CPL必須小于或等于門的DPL。這個(gè)限制可以防止運(yùn)行在特權(quán)級(jí)3的應(yīng)用程序使用軟件中斷訪問(wèn)重要的異常處理過(guò)程,例如頁(yè)錯(cuò)誤處理過(guò)程,假設(shè)這些處理過(guò)程已被存放在更高特權(quán)級(jí)的代碼段中。對(duì)于硬件產(chǎn)生的中斷和處理器檢測(cè)到的異常,處理器會(huì)忽略中斷門和陷阱門中的DPL。
因?yàn)楫惓:椭袛嗤ǔ2粫?huì)定期發(fā)生,因此這些有關(guān)特權(quán)級(jí)的規(guī)則有效地增強(qiáng)了異常和中斷處理過(guò)程能夠運(yùn)行的特權(quán)級(jí)限制。我們可以利用以下技術(shù)之一來(lái)避免違反特權(quán)級(jí)保護(hù):
異常或中斷處理程序可以存放在一個(gè)一致性代碼段中。這個(gè)技術(shù)可以用于只需訪問(wèn)堆棧上數(shù)據(jù)的處理過(guò)程(如除出錯(cuò)異常)。如果處理程序需要數(shù)據(jù)段中的數(shù)據(jù),那么特權(quán)級(jí)3必須能夠訪問(wèn)這個(gè)數(shù)據(jù)段。但這樣一來(lái)就沒(méi)有保護(hù)可言了。
處理過(guò)程可以放在具有特權(quán)級(jí)0的非一致代碼段中。這種處理過(guò)程總是可以執(zhí)行的,與被中斷程序或任務(wù)的當(dāng)前特權(quán)級(jí)CPL無(wú)關(guān)。
(2)異常或中斷處理過(guò)程的標(biāo)志使用方式
當(dāng)通過(guò)中斷門或陷阱門訪問(wèn)一個(gè)異常或中斷處理過(guò)程時(shí),處理器會(huì)在把EFLAGS寄存器內(nèi)容保存到堆棧上之后清除EFLAGS中的TF標(biāo)志。清除TF標(biāo)志可以防止指令跟蹤影響中斷響應(yīng)。而隨后的IRET指令會(huì)用堆棧上的內(nèi)容恢復(fù)EFLAGS的原TF標(biāo)志。
中斷門與陷阱門唯一的區(qū)別在于處理器操作EFLAGS寄存器IF標(biāo)志的方法。當(dāng)通過(guò)中斷門訪問(wèn)一個(gè)異常或中斷處理過(guò)程時(shí),處理器會(huì)復(fù)位IF標(biāo)志以防止其他中斷干擾當(dāng)前中斷處理過(guò)程。隨后的IRET指令則會(huì)用保存在堆棧上的內(nèi)容恢復(fù)EFLAGS寄存器的IF標(biāo)志。而通過(guò)陷阱門訪問(wèn)處理過(guò)程并不會(huì)影響 IF標(biāo)志。
(3)執(zhí)行中斷處理過(guò)程的任務(wù)
當(dāng)通過(guò)IDT表中任務(wù)門訪問(wèn)異常或中斷處理過(guò)程時(shí),就會(huì)導(dǎo)致任務(wù)切換。從而可以在一個(gè)專用任務(wù)中執(zhí)行中斷或異常處理過(guò)程。IDT表中的任務(wù)門引用 GDT中的TSS描述符。切換到處理過(guò)程任務(wù)的方法與普通任務(wù)切換一樣。由于本書(shū)討論的Linux操作系統(tǒng)沒(méi)有使用這種中斷處理方式,因此這里不再贅述。
4.6.10 中斷處理任務(wù)
當(dāng)通過(guò)IDT中任務(wù)門來(lái)訪問(wèn)異常或中斷處理過(guò)程時(shí)就會(huì)導(dǎo)致任務(wù)切換。使用單獨(dú)的任務(wù)來(lái)處理異常或中斷有如下好處:
被中斷程序或任務(wù)的完整上下文會(huì)被自動(dòng)保存。
在處理異常或中斷時(shí),新的TSS可以允許處理過(guò)程使用新特權(quán)級(jí)0的堆棧。在當(dāng)前特權(quán)級(jí)0的堆棧已毀壞時(shí)如果發(fā)生了一個(gè)異常或中斷,那么在為中斷過(guò)程提供一個(gè)新特權(quán)級(jí)0的堆棧條件下,通過(guò)任務(wù)門訪問(wèn)中斷處理過(guò)程能夠防止系統(tǒng)崩潰。
通過(guò)使用單獨(dú)的LDT給中斷或異常處理任務(wù)獨(dú)立的地址空間,可以把它與其他任務(wù)隔離開(kāi)來(lái)。
使用獨(dú)立任務(wù)處理異常或中斷的不足之處是:在任務(wù)切換時(shí)必須對(duì)大量機(jī)器狀態(tài)進(jìn)行保存,使得它比使用中斷門的響應(yīng)速度要慢,導(dǎo)致中斷延時(shí)增加。
IDT中的任務(wù)門會(huì)引用GDT中的TSS描述符,如圖4-30所示。切換到句柄任務(wù)的過(guò)程與普通任務(wù)切換過(guò)程相同。到被中斷任務(wù)的反向鏈接會(huì)被保存在句柄任務(wù)TSS的前一任務(wù)鏈接字段中。如果一個(gè)異常會(huì)產(chǎn)生一個(gè)出錯(cuò)碼,則該出錯(cuò)碼會(huì)被復(fù)制到新任務(wù)堆棧上。
?圖4-30 中斷處理任務(wù)切換
當(dāng)異常或中斷句柄任務(wù)用于操作系統(tǒng)中時(shí),實(shí)際上有兩種分派調(diào)度任務(wù)的機(jī)制:操作系統(tǒng)軟件調(diào)度和處理器中斷機(jī)制的硬件調(diào)度。使用軟件調(diào)度方法時(shí)需要考慮到中斷開(kāi)啟時(shí)采用中斷處理任務(wù)。
中斷信號(hào)的作用. 使CPU轉(zhuǎn)而去運(yùn)行正常控制流之外的代碼.為了它.就要在內(nèi)核態(tài)堆棧保存程序計(jì)數(shù)器的當(dāng)前值(eip和cs寄存器).并把與中斷類型相關(guān)的一個(gè)地址放在程序計(jì)數(shù)器.中斷處理與進(jìn)程切換的差異:由中斷或異常處理程序執(zhí)行的代碼不是一個(gè)進(jìn)程,而是內(nèi)核控制路徑.代表中斷發(fā)生時(shí)正在運(yùn)行的進(jìn)程執(zhí)行.其比進(jìn)程"輕". 中斷和異常 中斷: 可屏蔽中斷(maskable): I/O設(shè)備發(fā)出的中斷請(qǐng)求(irq)都屬于.可處于兩種狀態(tài):屏蔽的/非屏蔽的.非屏蔽中斷(nonmaskable): 只有幾個(gè)危急事件才引起.總是由CPU辨認(rèn). 異常: 處理器探測(cè)異常:當(dāng)CPU執(zhí)行指令時(shí)探測(cè)到一個(gè)反常條件所產(chǎn)生的異常. 根據(jù)保存在eip寄存器中的值,分為3種; 1)故障(fault):通常可以被糾正.eip中保存的是引起故障的指令地址.糾正后會(huì)重新執(zhí)行該條指令. ; 2)陷阱(trap):在陷阱指令執(zhí)行后立刻報(bào)告.內(nèi)核把控制器返回給程序后可以繼續(xù)他的執(zhí)行而不失連貫性. eip保存的是隨后要執(zhí)行的指令地址.只有當(dāng)沒(méi)有必要重新執(zhí)行已終止的指令時(shí)(通常為了調(diào)試程序)時(shí)才觸發(fā)陷阱. ; 3)異常中止(abort):不能在eip中保存引起異常的指令所在的確切位置.用于報(bào)告嚴(yán)重的錯(cuò)誤.異常中止處理程序會(huì)強(qiáng)制受影響的進(jìn)程終止.編程異常: 在編程者發(fā)出請(qǐng)求時(shí)發(fā)生.將其作為陷阱來(lái)處理.也叫軟中斷.用途:1)執(zhí)行系統(tǒng)調(diào)用.2)給調(diào)試程序通報(bào)一個(gè)特定的事件. 每個(gè)中斷和異常由0~255之間的一個(gè)數(shù)來(lái)標(biāo)示.稱為向量(vector).只有可屏蔽中斷的向量可以通過(guò)編程改變.其余都是固定的. IRQ和中斷:能發(fā)出中斷的設(shè)備都有一個(gè)IRQ的輸出線.所有IRQ線都與一個(gè)可編程中斷控制器(PIC)的硬件電路的輸入引腳相連.可以有選擇地禁止每條IRQ線.可對(duì)PIC編程從而禁止IRQ.禁止的中斷不丟失.一旦激活,PIC就把他們發(fā)送到CPU.該特性運(yùn)行中斷處理程序逐次處理同一類型的IRQ.為了發(fā)揮SMP體系的并行性,能夠把中斷傳遞給每個(gè)CPU很重要.所以引入了I/O高級(jí)可編程控制器(I/O APIC)的組件.所有CPU都含有一個(gè)本地APIC,通過(guò)APIC總線(在系統(tǒng)總線上)連接到外部的I/O APIC.還支持CPU產(chǎn)生處理器間中斷(IPI),可以利用它來(lái)在CPU之間交換消息.中斷描述符表:IDT是一個(gè)系統(tǒng)表,它與每一個(gè)中斷或異常向量相聯(lián)系.每一個(gè)向量在表中有相應(yīng)的中斷或異常處理程序的入口地址.最多需要256*8=2048字節(jié)來(lái)存放IDT. idtr寄存器指定IDT的線性基地址及其最大長(zhǎng)度,從而使IDT可以位于內(nèi)存中的任何地方.分為3種類型: 1)任務(wù)門:信號(hào)發(fā)生時(shí),必須取代當(dāng)前進(jìn)程的那個(gè)進(jìn)程的TSS選擇符存放在任務(wù)門中. ;2)中斷門:包含段選擇符和處理程序的段內(nèi)偏移量.當(dāng)CPU控制權(quán)轉(zhuǎn)移到一個(gè)適當(dāng)?shù)臄嗪?清除IF標(biāo)志來(lái)關(guān)閉將來(lái)會(huì)發(fā)生的可屏蔽中斷 ;3)陷阱門:與中斷門相似,但控制權(quán)傳遞到一個(gè)適合的CPU時(shí)不修改IF標(biāo)志.? Linux利用中斷門處理中斷,利用陷阱門處理異常.注意: "Double fault"異常是唯一由任務(wù)們處理的異常.表示一種內(nèi)核錯(cuò)誤. 中斷和異常處理程序的嵌套執(zhí)行. 必須保證中斷處理程序永不阻塞,即中斷處理程序運(yùn)行期間不能發(fā)生進(jìn)程切換.因?yàn)榍短椎膬?nèi)核控制路徑恢復(fù)執(zhí)行時(shí)需要的數(shù)據(jù)都存放在當(dāng)前線程的內(nèi)核態(tài)堆棧上.一個(gè)中斷處理程序可以搶占其他的中斷處理程序和異常處理程序.異常處理程序從不搶占中斷處理程序. 初始化中斷描述符表 過(guò)程: 1)在初始化系統(tǒng)時(shí)把IDT表的初始地址裝入idtr寄存器,并初始化表中的每一項(xiàng).; 2)int指令用于在用戶態(tài)進(jìn)程發(fā)出一個(gè)中斷信號(hào),為了防止模擬非法的中斷,將門描述符的DPL=0.; 3)在用戶態(tài)進(jìn)程必須要能夠發(fā)出一個(gè)編程異常時(shí),將門的SPL=3。Linux中的分類: 中斷門(DPL=0,所有LInux中斷處理程序都通過(guò)中斷門激活,并限制在內(nèi)核態(tài)); 系統(tǒng)門(DPL=3,用來(lái)激活3個(gè)linux異常處理程序); 系統(tǒng)中斷門(DPL=3,激活int3的異常處理程序); 陷阱門(DPL=0,激活大部分的異常處理程序); 任務(wù)門(DPL=0,"Double Fault的異常處理).idt的初始化分為兩步:1)將256個(gè)表項(xiàng)用同一個(gè)中斷門(即指向ignore_int()中斷處理程序:其是一個(gè)空的處理程序)來(lái)填充.2)用有意義的陷阱和中斷處理程序來(lái)代替空處理程序. 異常處理 大部分異常都解釋成為出錯(cuò)條件.當(dāng)異常發(fā)生時(shí),內(nèi)核向引起異常的進(jìn)程發(fā)送一個(gè)信號(hào)向它通知一個(gè)反常條件.特殊情況: 1)"Device not availeble" 2)"Page Fault"該異常推遲給進(jìn)程分配新的頁(yè)框,直到不能再推遲位置.異常處理程序的標(biāo)準(zhǔn)結(jié)構(gòu): 1)在內(nèi)核態(tài)堆棧中保存大多數(shù)寄存器的內(nèi)容; 2)用C函數(shù)處理異常; 3)通過(guò)ret_from_exception函數(shù)從異常處理程序退出. 中斷處理 由于一個(gè)進(jìn)程被掛起好久后中斷才到達(dá),因此一個(gè)完全無(wú)關(guān)的進(jìn)程可能正在運(yùn)行.所以發(fā)送信號(hào)給當(dāng)前進(jìn)程是無(wú)用的.中斷處理依賴于中斷類型:1)I/O中斷(查詢?cè)O(shè)備以確定適當(dāng)?shù)牟僮鬟^(guò)程); 2)時(shí)鐘中斷(該中斷告訴內(nèi)核一個(gè)固定的時(shí)間間隔已經(jīng)過(guò)去,作為I/O中斷處理) ;3)處理器間中斷.I/O中斷處理:要能給多個(gè)設(shè)備同時(shí)提供服務(wù).實(shí)現(xiàn): 1)IRQ共享(每個(gè)ISR(中斷服務(wù)例程)是一個(gè)與單獨(dú)設(shè)備(共享IRQ線)相關(guān)的函數(shù),因?yàn)闊o(wú)法預(yù)知那個(gè)特定的設(shè)備產(chǎn)生IRQ,所以,中斷處理程序執(zhí)行多個(gè)ISR,以驗(yàn)證它的設(shè)備是否需要關(guān)注,如果是,當(dāng)設(shè)備產(chǎn)生中斷時(shí)就執(zhí)行所需的操作); 2)IRQ動(dòng)態(tài)分配(一條IRQ線在可能的最后時(shí)刻才與一個(gè)設(shè)備相關(guān)聯(lián).這樣,即使幾個(gè)設(shè)備并不共享IRQ線,但同一IRQ向量也可以由這幾個(gè)設(shè)備在不同時(shí)刻使用). 一個(gè)中斷處理程序正在執(zhí)行時(shí),相應(yīng)的IRQ線上發(fā)出的信號(hào)被暫時(shí)忽略; 中斷處理程序所代表的進(jìn)程必須是出于Task_Running態(tài)的; 其不能執(zhí)行任何阻塞過(guò)程.中斷要執(zhí)行的操作: 1)緊急的(在禁止可屏蔽中斷下立即執(zhí)行); 2)非緊急的(在開(kāi)中斷下立即執(zhí)行); 3)非緊急可延遲的(由獨(dú)立的函數(shù)執(zhí)行).步驟:1)在內(nèi)核態(tài)堆棧中保存IRQ的值和寄存器的內(nèi)容; 2)為正在給IRQ線服務(wù)的PIC發(fā)送一個(gè)應(yīng)答來(lái)允許PIC進(jìn)一步發(fā)出中斷; 3)執(zhí)行共享這個(gè)IRQ的所有設(shè)備的ISR; 4)跳到ret_from_intr()的地址后終止.IRQ數(shù)據(jù)結(jié)構(gòu): 1)意外中斷:中斷內(nèi)核沒(méi)有處理的中斷.原因是與某個(gè)IRQ線相關(guān)的ISR不存在或者與某個(gè)中斷線相關(guān)的所有例程都識(shí)別不出來(lái).當(dāng)一條IRQ線上的意外中斷次數(shù)過(guò)多時(shí),就禁用這條IRQ線. 2)IRQ在多CPU系統(tǒng)上的分發(fā):對(duì)稱多處理器模型(SMP).一般情況下,內(nèi)核能夠公平地在CPU間分發(fā)中斷.但是在某些情況下,Linxu需要使用kirqd的內(nèi)核線程來(lái)糾正IRQ的自動(dòng)分配.其利用了CPU的IRQ親和力:通過(guò)修改I/O APIC的中斷重定向表表項(xiàng),可以吧中斷信號(hào)發(fā)送到某個(gè)特定的CPU上. CPU間中斷處理:IPI不通過(guò)IRQ線傳輸,而是作為信號(hào)直接放在連接所有CPU本地APIC總線上. 類型: 1)Call_Function_Vector(發(fā)往不包含發(fā)送者的所有CPU,強(qiáng)制這些CPU運(yùn)行發(fā)送者傳遞過(guò)來(lái)的函數(shù)). 2)Reschedule_Vector(從中斷返回后,所有的重新調(diào)度都自動(dòng)運(yùn)行); 3)Invalidate_TLB_Vector(強(qiáng)制TLB無(wú)效,來(lái)刷新CPU的TLB). 軟中斷及tasklet: 可延遲中斷可以在開(kāi)中斷的情況下執(zhí)行.把可延遲中斷從中斷處理程序中抽出來(lái)有助于使內(nèi)核保持較短的響應(yīng)時(shí)間.Linux通過(guò)兩種非緊迫,可中斷內(nèi)核函數(shù):1)可延遲函數(shù);2)通過(guò)工作隊(duì)列來(lái)執(zhí)行的函數(shù).tasklet是在軟中斷之上實(shí)現(xiàn)的.軟中斷的分配是靜態(tài)的,tasklet的分配和初始化是在運(yùn)行時(shí).軟中斷是可重入函數(shù)并使用自旋鎖來(lái)保護(hù)數(shù)據(jù),其實(shí)可以并行在多CPU上執(zhí)行的,tasklet總是串行執(zhí)行,但是不同類型的tasklet可以并發(fā)執(zhí)行,其不必是可重入的.四種操作:1)初始化;2)激活;3)屏蔽;4)執(zhí)行.激活和執(zhí)行被綁定在一個(gè)CPU上,雖然可以更好地利用CPU的Cache,但是有潛在的危險(xiǎn)性(一個(gè)CPU很忙,但其他的很閑).軟中斷:使用下標(biāo)(共6個(gè))來(lái)表示優(yōu)先級(jí).softirq_action[32] ?softirq_vec數(shù)組.優(yōu)先級(jí)是下標(biāo),所以只有前6元素個(gè)有效.另外,thread_info中有一個(gè)preempt_count字段來(lái)跟蹤內(nèi)核搶占和內(nèi)核控制路徑的嵌套.每個(gè)CPu都有自己的ksoftirqd/n內(nèi)核線程.其為了解決以下問(wèn)題:軟中斷函數(shù)可以重新激活自己,軟中斷的連續(xù)高流量可能會(huì)產(chǎn)生問(wèn)題.不然就要選擇以下兩種之一的策略:1)忽略do_softirq()運(yùn)行時(shí)新出現(xiàn)的軟中斷,此種情況的等待是不可接受的;2)不斷地重新檢查掛起的軟中斷,這種情況下,do_softirq()函數(shù)就會(huì)一直不返回,用戶態(tài)程序?qū)嶋H上停止執(zhí)行.解決:do_softirq()函數(shù)確定哪些軟中斷是掛起的,并執(zhí)行他們的韓素華.如果已經(jīng)執(zhí)行的軟中斷又被激活,則do_softirq()喚醒內(nèi)核線程并終止.內(nèi)核線程有較低的優(yōu)先級(jí),因此用戶程序有就會(huì)運(yùn)行.但是,如果機(jī)器空閑(沒(méi)有用戶態(tài)程序需要運(yùn)行時(shí)),掛起的軟中斷就很快被執(zhí)行.tasklet:是I/O驅(qū)動(dòng)程序中實(shí)現(xiàn)可延遲函數(shù)的首選. 工作隊(duì)列 用來(lái)代替任務(wù)隊(duì)列.允許內(nèi)核函數(shù)被激活,而且稍后由一種叫做工作者線程的特殊內(nèi)核線程來(lái)執(zhí)行.可延遲函數(shù)運(yùn)行在中斷上下文中,而工作隊(duì)列中的函數(shù)運(yùn)行在進(jìn)程上下文中.執(zhí)行可阻塞函數(shù)的方式是在進(jìn)程上下文中運(yùn)行,因?yàn)樵谥袛嗌舷挛闹胁豢赡馨l(fā)生進(jìn)程切換.兩者都不能訪問(wèn)進(jìn)程的用戶態(tài)地址空間.
總結(jié)
以上是生活随笔為你收集整理的中断和异常的区别的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。