中斷

中斷（Interrupt），又稱插斷，在電腦科學中是指處理器接收到來自硬體或軟體的信號，提示發生了某個事件，應予以注意，這種情況就稱為中斷。

通常，在接收到來自外圍硬體（相對於中央處理器和記憶體）的信號，或來自軟體的信號之後，處理器將會進行相應的硬體／軟體處理。發出這樣的信號稱為進行中斷請求（interrupt request，IRQ）。硬體中斷導致處理器通過一個執行資訊切換（context switch）來保存執行狀態（以程序計數器和程序狀態字等寄存器資訊為主）；軟體中斷則通常作為CPU指令集中的一個指令，以可編程的方式直接指示這種執行資訊切換，並將處理導向一段中斷處理代碼。中斷在電腦多任務處理，尤其是即時系統中尤為有用。這樣的系統，包括運行於其上的作業系統，也稱「中斷驅動」（interrupt-driven）。

## 總覽

中斷是用以提高電腦工作效率、增強電腦功能的一項重要技術。最初引入硬體中斷，只是出於性能上的考量。如果電腦系統沒有中斷，則處理器與外部設備通信時，它必須在向該設備發出指令後進行忙等待（Busy waiting），反覆輪詢該設備是否完成了動作並返回結果。這就造成了大量處理器周期被浪費。引入中斷以後，當處理器發出設備請求後就可以立即返回以處理其他任務，而當設備完成動作後，發送中斷信號給處理器，後者就可以再回過頭獲取處理結果。這樣，在設備進行處理的周期內，處理器可以執行其他一些有意義的工作，而只付出一些很小的切換所引發的時間代價。後用於CPU外部與內部緊急事件的處理、機器故障的處理、時間控制等多個方面，並產生通過軟體方式進入中斷處理（軟中斷）的概念。

在硬體實現上，中斷可以是一個包含控制線路的獨立系統，也可整合進存儲器子系統中。對於前者，在IBM個人機上，廣泛使用可編程中斷控制器（Programmable Interrupt Controller，PIC）來負責中斷響應和處理。PIC連接在若干中斷請求設備和處理器的中斷引腳之間，從而實現對處理器中斷請求線路（多為一針或兩針）的復用。作為另一種中斷實現的形式，即存儲器子系統實現方式，可以將中斷埠映射到存儲器的地址空間，這樣對特定存儲器地址的訪問實際上是中斷請求。

中斷可分為如下幾種：

硬體中斷（Hardware Interrupt）：

- 可屏蔽中斷（maskable interrupt）。硬體中斷的一類，可通過在中斷屏蔽寄存器中設定位掩碼來關閉。
- 非可屏蔽中斷（non-maskable interrupt，NMI）。硬體中斷的一類，無法通過在中斷屏蔽寄存器中設定位掩碼來關閉。典型例子是時鐘中斷（一個硬體時鐘以恆定頻率—如50Hz—發出的中斷）。
- 處理器間中斷（interprocessor interrupt）。一種特殊的硬體中斷。由處理器發出，被其它處理器接收。僅見於多處理器系統，以便於處理器間通信或同步。
- 偽中斷（spurious interrupt）。一類不希望被產生的硬體中斷。發生的原因有很多種，如中斷線路上電氣信號異常，或是中斷請求設備本身有問題。

軟體中斷（Software Interrupt）：

- 軟體中斷。是一條CPU指令，用以自陷一個中斷。由於軟中斷指令通常要運行一個切換CPU至內核態（Kernel Mode/Ring 0）的子例程，常用於實現系統調用（System call）。

處理器通常含有一個內部中斷屏蔽位，並允許通過軟體來設定。一旦完成設定，所有外部中斷都將被系統忽略。這個屏蔽位的存取速度顯然快於中斷控制器上的中斷屏蔽寄存器，因此可提供更快速地中斷屏蔽控制。

如果一個中斷使得機器處於一種確定狀態，則稱為精確中斷（precise interrupt）。精確中斷須保證：

- 程序計數器的值保存在已知位置。
- 程序計數器所指向的指令之前的所有指令已執行完畢。
- 程序計數器所指向的指令之後的所有指令不可執行。如果中斷信號到來後而轉入處理前發生了任何針對寄存器／記憶體的更改，都必須予以還原。
- 程序計數器所指向的指令地執行狀態已知。

倘無法滿足以上條件，此中斷稱為非精確中斷（imprecise interrupt）。

中斷儘管可以提高電腦處理性能，但過於密集的中斷請求／響應反而會影響系統性能。這類情形稱為中斷風暴（interrupt storm）。

## 中斷的種類

### 狀態觸發

在依狀態觸發的中斷系統中，一個等待響應的中斷會在中斷請求線路上以特定的電位標示，如高電位（1）或低電位（0）。當一個設備希望發送中斷信號時，它驅動中斷請求線路至相應的電位，並在CPU發出強制停止命令或處理所請求的中斷事件之前始終保持。

一般而言，處理器在總線周期的特定時點響應中斷的輸出/ 輸入。如果在某次採樣時刻中斷尚未觸發，則在下一次採樣前，處理器都不會認為有中斷發生。可以應用這個特性，避免響應在噪音較高的線路上出現的偽中斷。

中斷設備可設計成與其他設備共享一條狀態觸發中斷線路。中斷線路應該包含一個特定的升／降壓電阻，用於在無中斷請求時為線路電位復位。中斷設備在請求中斷時會保持中斷線路為有效電位，而沒有請求中斷時則令該線路置空。只要有一個或以上的設備發出中斷信號，線路都會處於有效的電位。

由於可共享線路的便利，一些應用傾向於使用該類中斷。當CPU檢測到中斷線路被斷言後，就會逐一檢查各共享設備，直至發現請求設備並處理之。當處理完畢後，繼續檢查中斷線路，倘中斷線路仍為有效電平則重複之前的步驟。在檢查中斷設備的順序上也可做一定規劃，比如優先檢查那些頻繁請求中斷的設備，以加快中斷處理，改善系統性能。

此類中斷模式也有嚴重問題。只要還有任何設備的中斷請求尚未處理，線路就會一直保持有效電平狀態，而這將導致CPU沒有機會去探查其他設備所發生的狀態變化。推遲服務低優先級設備也不可行，因為這會防止對高優先級設備的探查。倘若在線路上有一個設備持續發送請求而CPU不知道怎樣對其進行服務，則這個設備就會持久並排他地占有中斷線路。

早期的PCI（外設互連標準）標準出於上述效率層面的理由規定其周邊須使用狀態觸發中斷。

### 邊沿觸發

在依邊沿觸發的中斷系統中，中斷設備通過向中斷線路發送一個脈衝來表示其中斷請求。脈衝可以為上升沿或下降沿。在發送完脈衝後設備立即釋放中斷線路。如果這個脈衝太短，以至於I/O輪詢不足以確保知悉其存在，則有必要使用專門的硬體設備來輔助對邊沿觸發的探查。

中斷設備可設計成與其他設備共享一條邊沿觸發中斷線路。中斷線路應該包含一個特定的上拉／下拉電阻，用於在無中斷請求時為線路電平復位。設備通過發送一個脈衝作為其中斷信號。如果多個設備在近乎相同的時間內發送脈衝，則會在線路上合併成一個信號。為防止中斷丟失，CPU必須在一個脈衝之後的下一個邊沿（如果脈衝為上升沿則其下一個邊沿就是下降沿）立即觸發。收到中斷請求後CPU立即查詢各中斷設備以定位中斷源。

邊沿觸發中斷不會遭受狀態觸發中斷在共享中斷引腳時所遇到的問題。低優先級設備的服務可任意推遲，而CPU仍會收到高優先級設備的中斷請求。一個即便是頻繁發生的偽中斷也不會影響正常設備的中斷請求。但是，邊沿觸發中斷容易丟失，特別是當中斷被有意屏蔽時。在不引入鎖存器的情況下，在屏蔽時段發送的中斷信號不可恢復。在早期的電腦系統中因為中斷丟失而導致處理不能繼續的情況時有發生。現代中斷硬體多包含有一個或一組中斷狀態鎖存器，用以暫存一逝而過的中斷請求。在對邊沿觸發中斷硬體進行編程時，應檢查這些中斷狀態寄存器以確保請求事件不會丟失。

已經過時的ISA（工業標準架構）標準使用邊沿觸發中斷，但不規定其實現必須能夠共享線路。

### 混合模式

一些系統使用狀態觸發與邊沿觸發兼顧的混合中斷模式。其硬體不但探測脈衝，也驗證中斷信號是否保持一段時間。

非可屏蔽中斷多使用混合模式。由於非可屏蔽中斷多與重要的系統異常事件相關，十分有必要確保對其中斷信號的捕捉快速而正確。這種兩步驟探查方式能夠有效減輕錯誤中斷或遺失中斷給系統帶來的影響。

### 消息信號（Message-signalled）

消息信號式中斷並不直接通過對特定物理線路進行斷言／發送脈衝來通知一個中斷。這類中斷設備通過在某種通訊媒介（一般是電腦總線）上發送一個有邏輯含義的消息（一串／排比特碼）來實現中斷請求。中斷消息可以是通訊總線協議中專門為中斷預留的類型，也可以是一個現有的類型，如記憶體寫操作。

消息信號式中斷在行為上與邊沿觸發中斷類似，因為它們都是發送一個瞬間的信號。中斷處理軟體的對此類中斷的處理方式也類似於邊沿觸發中斷：如果兩個消息相同，則可以合併。消息信號中斷向量（中斷處理程序的地址）也可以共享，就如同物理線路可以被共享一般。

由於中斷消息的識別基於特定的比特碼序列而不是物理線路上的單個信號，可以有效地通過設定不同的中斷比特碼來劃分和處理不同類型的中斷。另外，使用串行或並行總線都可以傳遞中斷消息。

由於無論狀態觸發還是邊沿觸發都在使用共享線路時存在線路競爭問題，而物理線路數本身也是稀缺資源，不可能被各中斷源分別獨占，所以消息信號中斷是一個解決此問題的較好替代方案。消息信號中斷的本質差別在於其中斷請求運行在單純的物理線路之上，具有特定的邏輯含義。這種區別好比電腦網絡體系中第一層（物理層）和第二層（鏈路層）的差別。使用具有邏輯含義的中斷請求，可以把諸請求區分開來，形成多條虛通路，而運行於一條物理總線之上。

PCI Express串行總線標準即使用此種中斷。

## 應用

### 常見應用

中斷的典型應用包括系統時鐘、磁碟輸入輸出操作、斷電信號以及軟體自陷等。

- 系統時鐘通過一個計數器（多基於某種振動頻率）定期向CPU發出中斷，CPU通過專門的時鐘中斷處理程序來保持計時。現代作業系統對系統時鐘的另一個主要應用是為進程切換提供時機。一旦時鐘中斷發生，程序計數器會被自動壓棧，而此時作業系統就有機會將程序狀態及記憶體映像轉存至別處，並調用進程調度程序來選擇下一個進程，並將其進程狀態，包括程序計數器，導入寄存器。這樣下一個程序就可以運行。應注意進程調度程序的調度時機不止於時鐘中斷。
- 磁碟中斷標識某個磁碟設備完成了數據的發送／接收。磁碟中斷發生後，等待這個中斷的進程可以（但未必，這取決於進程調度程序當時的判斷）繼續執行。
- 斷電中斷指示電腦能源即將喪失，電腦可以相應中斷程序作有序的關機處理。

### 實例：8086A的中斷系統

8086A處理器是INTEL公司於20世紀70年代末推出的一款16位處理器。該處理器在中斷處理上有如下特色，這些特色也為後續INTEL處理器所共有。

#### 引腳

8086A提供兩個中斷引腳：第17引腳NMI，和第18引腳INTR。前者用於接收非可屏蔽中斷，後者則接收可屏蔽中斷。通常，INTR引腳與中斷控制器（如8259A）相連，後者再分別與各設備的中斷請求引腳連接。除了INTR外，8086A還將自身的16位地址總線（配合M/IO引腳並通過解碼器）及8位數據總線與8259A連接，並將INTA引腳與8259A的同名引腳相連。

#### 中斷向量表

在存儲器地址空間中，規定最低的1K空間，即00000H到003FFH為中斷向量表。全表共含256個中斷向量，每個向量的長度為4位元組，包含中斷處理程序的起始地址。共有從0到255共256個中斷類型碼，每個中斷類型碼對應的中斷向量所在地址為該類型碼乘以4。舉例而言，如果中斷類型碼為1，則對應中斷向量所在地址為00004H；如果中斷類型碼為33，則對應中斷向量所在地址為00084H。這樣，如果已知一個中斷類型碼，則需要通過兩次地址轉換（中斷類型碼到中斷向量表地址；中斷向量表地址到中斷處理程序地址）才能到達中斷處理程序。另外應注意每一個中斷向量所包含的地址是以低二字節存儲偏移量，高二字節存儲段地址的形式存儲目標地址值的。

在全部256個中斷中，前32個（0—31）為硬體系統所預留。後224個可由使用者設定。在初始化8259A時，可設定其上各中斷引腳（共8條）對應的中斷類型碼。同時，將對應此中斷之處理程序的起始地址保存在該中斷類型碼乘4的地址位中，作為中斷向量。

在INTEL後續的32位CPU中，使用中斷描述符表來代替中斷向量表。中斷描述符表的起始地址由中斷描述符表寄存器（IDTR）來定位，因此不再限於底部1K位置。另一方面，中斷描述符表的每一個項目——稱作門描述符——除了含有中斷處理程序地址資訊外，還包括許多屬性／類型位。門描述符分為三類：任務門、中斷門和自陷門。CPU對不同的門有不同的調用（處理）方式。

##### 中斷處理過程

在實際運行中，一旦設備通過某引腳N向8259A發出中斷指令，後者便向8086A的INTR引腳發送中斷信號。8086A通過INTA引腳通知8259A中斷有效（這個過程實際上還包括對此8259A的選址），後者即通過地址總線將對應引腳N的中斷類型碼（已預先存好，見上節）發送給CPU。CPU得到中斷類型碼後，先進行現場保護，主要包括：

- 狀態寄存器FLAGS壓棧（同時堆棧寄存器SP-2）。
- 關閉中斷（將FLAGS寄存器的IF位置零）。
- 將當前代碼段寄存器CS和程序計數器IP壓棧（同時堆棧寄存器SP-4）。

現場保護完成後，CPU開始按照前述的兩步驟翻譯中斷程序入口地址。在得到中斷處理程序地址之後但調用中斷處理程序之前，CPU會再檢查一下NMI引腳是否有信號，以防在剛才的處理過程中忽略了可能的NMI中斷。NMI的優先級始終高於INTR。

中斷處理程序雖然是由程式設計師編寫，但須循一定規範。作為例程，中斷處理程序應該先將各寄存器資訊（除了IP和CS，此二寄存器現已指向當前中斷程序）壓入堆棧予以保存，這樣才能在中斷處理程序內部使用這些寄存器。在程序結束時，應該按與壓棧保護時相反的順序彈出各寄存器的值。中斷程序的最後一句始終是IRET指令，這條指令將棧頂6個字節分別彈出並存入IP、CS和FLAGS寄存器，完成了現場的還原。

當然，如果是作業系統的中斷處理程序，則未必——通常不會——還原中斷前的狀態。這樣的中斷處理程序通常會在調用完寄存器保存例程後，調用進程調度程序（多由高級語言編寫），並決定下一個運行的進程。隨後將此進程的寄存器資訊（上次中斷時保存下來的）存入寄存器並返回。在中斷程序結束之後，主程序也發生了改變。

#### 相關指令

一些與中斷控制相關的指令包括：

- `CLI` 關閉中斷（實為將FLAGS的IF位置0）。
- `STI` 開啟中斷（實為將FLAGS的IF位置1）。
- `INT n` 調用中斷子程序，n為中斷類型碼。DOS系統有一個系統調用API即為INT 21H。
- `INT0` 先判別FLAGS的OF位是否為1，如是則直接調用類型為4的中斷子程序，用以處理溢出中斷。
- `IRET` 將棧頂6個字節分別彈出並存入IP、CS和FLAGS寄存器，用以返回中斷現場。

#### 其它

- 與中斷處理相對的是輪詢(Polling)