What is Interrupt?

Introduction

我們可以將 Interrupt 想成 device 版的 signal,signal 是用來讓 OS 通知 Applications 特定事件的到來,而 Interrupt(廣義)是讓 CPU 暫停當前執行流、轉交控制給 OS 的機制;Hardware Interrupt 是其中由外部 device 觸發的那一類

Interrupt Handler

在執行 interrupt handler 時,原 process 並不處於 running state 而是被踢回 ready state,因為此時 CPU 已經切換到 kernel mode 了所以是用 kernel stack。 作為對比,system call 雖然也是在 kernel 執行,但是是 process 主動呼叫的,所以仍算是該 process 正在執行(process 狀態還是 running state)

Why we need interrupt?

如果沒有 interrupt,OS 必須不斷 polling device registers 才知道 I/O 是否完成。這在 slow device 或 event 不頻繁的情境會浪費大量 CPU cycle。Interrupt 讓 CPU 平時可以跑其他 process,只有 device 真正有事時才切入 kernel 處理。

因此 interrupt 的本質是把等待成本從「CPU 主動輪詢」改成「hardware event 主動通知」。


Types of Interrupt

Hardware Interrupt

由外部裝置發出的信號,像是鍵盤按下、計時器到期、網卡收到封包

Asynchronous

CPU 無法預知此種 interrupt 的到來

Maskable, Nonmaskable, and Priority

Interrupt 不全都一樣緊急。現代 CPU 通常區分:

  • Nonmaskable interrupt (NMI):不能被忽略,通常保留給嚴重硬體錯誤,例如 unrecoverable memory error。
  • Maskable interrupt:可以暫時被 CPU mask 掉,常用於一般 device controller request。OS 在更新 critical kernel data structure 時可能暫時 mask,避免資料結構被中途打斷。

此外,interrupt priority 讓 high-priority interrupt 可以比 low-priority interrupt 先處理。例如 device FIFO 快滿時的 interrupt 通常比一般 system call trap 更緊急,因為拖太久可能直接丟資料。

FLIH and SLIH

Interrupt handler 常被分成兩層:

  • First-level interrupt handler (FLIH):處理最緊急、必須立刻做的事,例如保存狀態、確認 interrupt source、清除 device interrupt、把後續工作排入 queue。
  • Second-level interrupt handler (SLIH):稍後以較低優先權完成比較耗時的工作,例如把 kernel buffer 中的資料 copy 回 user space、喚醒 process。

這樣做的原因是 interrupt context 很敏感。若 high-priority handler 花太久,其他緊急 device event 可能延誤。因此 OS 會把「必須立刻做」和「可以稍後做」拆開。

Exception

CPU 偵測到錯誤或特殊狀況,像是 divide by zero, segmentation fault 之類的

Synchronous

因為這種 Exception 是因為某一條指令而產生

Software Interrupt / Trap

程式碼在 user space 做不到一些事情,這時候就需要執行一條特殊指令(syscall)來讓 CPU 切入 kernel mode (ring 0) 幫你做完後再轉回 user mode 並交還控制權給你


How does Interrupt works?

Prerequisite (boot time): Initialize Interrupt Vector Table (IVT)

OS 在開機時將各個 ISR 所在的記憶體位置寫到 IVT 上,讓 CPU 之後知道去哪裡找 ISR

Step 1: Device Raises an IRQ signal

Device 偵測到 event(像是鍵盤被按下)後會透過 interrupt-request line(一條硬體訊號線)送 IRQ (Interrupt Request) 給 PIC (Programmable Interrupt Controller),他會將對應的優先級和 Interrupt number 送給 CPU

Step 2: CPU detects the interrupt

CPU 會在完成每個 instruction 後檢查有沒有 IRQ

Step 3: CPU saves current state to the kernel stack

CPU 會先將 program counter, registers 資訊存到 kernel stack (per-CPU interrupt stack),這樣之後要回來執行原來的任務才知道之前執行到哪裡

Step 4: CPU queries the IVT for the ISR address

CPU 去 IVT 看看這個 Interrupt number 對應的 ISR 被存在哪裡(這個地址稱為 Interrupt vector

Step 5: CPU jumps to the ISR and executes the event

CPU 根據 IVT 記錄的記憶體位置跳到 ISR 存放位置並且執行去 handle event(像是去鍵盤讀取輸入之類的)

Step 6: ISR returns via iret

ISR 處理完事情後會呼叫 iret 這個特殊的 instruction 會將 CPU 在 step 3 儲存的 program state 回復過來並且繼續執行原來的任務