中斷

**中斷**（英語：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 得到中斷類型碼後，先進行現場保護，主要包括：

1. 狀態暫存器 FLAGS 壓棧（同時堆疊暫存器 SP-2）；
2. 關閉中斷（將 FLAGS 暫存器的 IF 位置零）；
3. 將當前代碼段暫存器 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)

## 參考