title: 인터럽트/예외 처리
date: 2025-06-26
category: arch
tags: [interrupt, exception, trap, fault, abort, NMI, ISR, IDT, PIC, APIC]
인터럽트/예외 처리
개요
인터럽트(Interrupt)와 예외(Exception)는 프로세서가 현재 실행 중인 코드를 중단하고 특수 처리 루틴으로 전환하게 만드는 하드웨어/소프트웨어 메커니즘이다. 인터럽트는 외부 디바이스(키보드, 디스크, 네트워크 등)가 시간에 민감한 이벤트를 프로세서에 알릴 때 사용되며, 예외는 프로세서 내부에서 잘못된 명령어 실행이나 메모리 접근 위반 등 특수한 조건이 발생했을 때 호출된다.
이 메커니즘은 현대 컴퓨터 시스템의 기반을 이루는 핵심 기술로, 운영 체제의 멀티태스킹, 디바이스 드라이버 동작, 시스템 호출 구현, 실시간 처리 등에 필수적이다. 인터럽트가 없으면 프로세서는 모든 디바이스의 상태를 주기적으로 확인해야 하며(polling), 이는 컴퓨팅 자원의 극심한 낭비를 초래한다. 1953년 UNIVAC 1103A에서 최초로 인터럽트가 도입된 이래, 오늘날의 복잡한 멀티코어 시스템에 이르기까지 지속적으로 발전해 왔다.
핵심 개념
인터럽트 분류
인터럽트와 예외는 발생 원인과 처리 방식에 따라 여러 유형으로 분류된다:
| 분류 | 발생 원인 | 동기/비동기 | 재시작 가능 | 예시 |
|---|---|---|---|---|
| 하드웨어 인터럽트 | 외부 디바이스의 전기적 신호 | 비동기 | 가능 | 키보드 입력, 디스크 I/O 완료, 타이머 |
| 소프트웨어 인터럽트 | 명령어 실행 중 발생 | 동기 | 가능 | 시스템 호출 (INT 0x80, SYSCALL) |
| Fault (결점) | 명령어 실행 불가 | 동기 | 가능 | 페이지 폴트, 보호 폴트 |
| Trap (트랩) | 의도적 디버깅 목적으로 발생 | 동기 | 다음 명령어부터 | 브레이크포인트, 시스템 호출 |
| Abort (중단) | 복구 불가능한 심각한 오류 | 동기/비동기 | 불가능 | 하드웨어 오류, 이중 폴트 |
인터럽트 벡터 테이블 (IVT/IDT)
각 인터럽트 유형에는 고유한 벡터 번호가 할당되며, 이 번호를 통해 처리 루틴의 주소를 찾는다:
- x86 (32비트): IDT(Interrupt Descriptor Table)에서 256개 벡터 지원
- x86-64: 64비트 IDT, 256개 벡터, 스택 스위칭 메커니즘 포함
- ARM (AArch64): VBAR_ELx(Vector Base Address Register)로 벡터 테이블 기반 설정
- RISC-V: mtvec(Machine Trap Vector) 레지스터로 벡터 테이블 지정
IDT 엔트리 구조 (x86-64):
┌─────────────────────────────────────┐
│ Offset[63:32] │ 4바이트
├─────────┬───┬─┬───┬─────────────────┤
│ Present │DPL│0│IST│ Offset[31:16] │ 2바이트
├─────────┴───┴─┴───┴─────────────────┤
│ Segment Selector │ 2바이트
├─────────────────────────────────────┤
│ Offset[15:0] │ 2바이트
└─────────────────────────────────────┘
Total: 16 bytes per entry
인터럽트 우선순위 (Priority)
시스템에는 여러 인터럽트 소스가 존재하며, 우선순위가 높은 것부터 처리된다:
| 우선순위 | 인터럽트 유형 | 설명 |
|---|---|---|
| 최고 | NMI (Non-Maskable Interrupt) | 절대 차단 불가, 하드웨어 오류, 전원 상실 경고 |
| 높음 | 하드웨어 인터럽트 (디바이스) | 디스크 I/O, 네트워크 패킷 수신 |
| 중간 | 소프트웨어 인터럽트 | 시스템 호출, 디버깅 트랩 |
| 낮음 | 프로세스 스케줄링 | 타이머 인터럽트에 의한 컨텍스트 스위치 |
인터럽트 마스킹 (Masking)
인터럽트를 선택적으로 차단하거나 허용하는 메커니즘:
- IF (Interrupt Flag) 비트: x86의 EFLAGS 레지스터에 위치, 하드웨어 인터럽트 전역 제어
- CLI (Clear Interrupt Flag): 인터럽트 비활성화
- STI (Set Interrupt Flag): 인터럽트 활성화
- NMI: 인터럽트 마스크 레지스터로도 차단 불가 (SPARC 예외)
- Programmable Interrupt Controller (PIC/APIC): 디바이스별 개별 마스킹 지원
인터럽트 통합 (Interrupt Coalescing)
인터럽트 통합은 여러 인터럽트 요청을 하나로 묶어 일괄 처리하는 기법으로, 높은 인터럽트 발생률로 인한 CPU 오버헤드를 줄이기 위해 사용된다:
- 시간 기반 통합: 일정 시간 윈도우 내의 인터럽트를 모아 한 번에 처리
- 개수 기반 통합: 지정된 개수의 인터럽트가 쌓이면 한 번에 처리
- 적응형 통합: 트래픽 부하에 따라 통합 파라미터를 동적으로 조정
- 주요 사용처: 고속 네트워크 카드(NIC), NVMe 스토리지 컨트롤러
- 트레이드오프: 지연 시간 증가 vs CPU 사용률 감소
스퓨리어스 인터럽트 (Spurious Interrupt)
스퓨리어스 인터럽트는 실제 인터럽트 소스가 존재하지 않는데도 프로세서가 인터럽트를 인식하는 현상이다. 주로 wired-OR 방식으로 연결된 레벨 트리거 인터럽트 회로에서 발생하며, 인터럽트 라인의 기생 커패시턴스(parasitic capacitance) 충방전 지연으로 인해 ISR 종료 후에도 인터럽트 신호가 완전히 해제되지 않아 발생한다. ISR 내에서 인터럽트 소스를 너무 늦게 클리어하면, 프로세서가 ISR을 빠져나온 직후 동일한 인터럽트를 다시 감지하게 된다.
스퓨리어스 인터럽트는 시스템 데드락(deadlock)이나 예측 불가능한 동작을 유발할 수 있으므로, ISR은 반드시 모든 인터럽트 소스를 확인하고 실제 요청이 없는 경우 아무 작업도 하지 않고 반환하도록 설계해야 한다. 잘못된 회로 설계, 높은 노이즈 레벨, 크로스토크(crosstalk), 타이밍 문제, 디바이스 에라타(errata)도 스퓨리어스 인터럽트의 원인이 될 수 있다.
인터럽트 누락 (Missing Interrupt)
인터럽트 누락은 하드웨어가 상태 변화에 대한 인터럽트를 생성하지 못해 운영체제가 무한정 대기하는 장애 모드이다. 특히 엣지 트리거 인터럽트에서 인터럽트가 마스킹된 동안 발생한 이벤트는 하드웨어 래치(latch)가 없는 경우 영구적으로 손실될 수 있다. 초기 컴퓨터 하드웨어에서 이러한 문제는 빈번한 시스템 정지(lockup)를 일으켰으며, 현대 하드웨어는 인터럽트 상태 레지스터를 통해 마스킹 기간 중 발생한 이벤트를 보존한다.
비교/분석
인터럽트 트리거 방식 비교
| 특성 | 레벨 트리거 (Level-triggered) | 엣지 트리거 (Edge-triggered) |
|---|---|---|
| 동작 방식 | 특정 로직 레벨 유지 시 인터럽트 발생 | 레벨 전이(rising/falling edge) 시 인터럽트 발생 |
| 공유 지원 | wired-OR 연결로 여러 디바이스 공유 가능 | 공유 시 펄스 합병 위험 |
| 스페어 인터럽트 | wired-OR 회로에서 발생 가능 | 발생 불가 |
| 누락 위험 | 없음 (레벨 유지 시 지속 발생) | 있음 (마스킹 중 이벤트 누락 가능) |
| 복잡도 | 낮음 | 높음 (상태 레지스터 필요) |
| 사용 예 | PCI, ISA (일부) | USB, PCIe, PS/2 |
인터럽트 처리 구조 비교
| 구조 | 특징 | 장점 | 단점 |
|---|---|---|---|
| 폴링 (Polling) | 주기적으로 디바이스 상태 확인 | 구조 단순 | CPU 자원 낭비, 지연 시간 긴 |
| 단일 핸들러 | 모든 인터럽트를 하나의 루틴에서 처리 | 구현 용이 | 우선순위 처리 복잡 |
| 벡터화 인터럽트 | 각 인터럽트에 고유 핸들러 할당 | 빠른 응답, 우선순위 처리 용이 | 메모리 사용 증가 |
| 공유 인터럽트 라인 | 여러 디바이스가 하나의 IRQ 공유 | IRQ 라인 절약 | 스페어 인터럽트 위험 |
x86 vs ARM 인터럽트 처리 비교
| 항목 | x86 (Intel/AMD) | ARM (AArch64) |
|---|---|---|
| 인터럽트 분류 | 하드웨어 인터럽트, Fault, Trap, Abort | IRQ, FIQ, SError, SVC/SWI |
| 벡터 테이블 | IDT (256 엔트리, 16바이트/엔트리) | VBAR_ELx (4개 엔트리/레벨) |
| 비동기 인터럽트 | IRQ, NMI | IRQ, FIQ, SError |
| 동기 예외 | Fault, Trap, Abort | SVC, WFI, data/prefetch abort |
| FIQ 지원 | 없음 (NMI로 대체) | 있음 (빠른 인터럽트, 백그라운드 세트 지원) |
| 인터럽트 컨트롤러 | APIC (로컬/글로벌) | GIC (Generic Interrupt Controller) |
x86 예외 유형 상세
| 예외 번호 | 이름 | 유형 | 설명 |
|---|---|---|---|
| #DE | Divide Error | Fault | 0으로 나누기 또는 오버플로우 |
| #DB | Debug | Trap/Fault | 디버그 레지스터 관련 |
| #NMI | Non-Maskable Interrupt | Interrupt | 비마스크 인터럽트 |
| #BP | Breakpoint | Trap | INT 3 명령어 실행 |
| #OF | Overflow | Trap | INTO 명령어 실행 |
| #BR | Bound Range Exceeded | Fault | BOUND 명령어 범위 초과 |
| #UD | Invalid Opcode | Fault | 정의되지 않은 명령어 |
| #NM | Device Not Available | Fault | FPU/x87 없음 |
| #DF | Double Fault | Abort | 예외 처리 중 추가 예외 발생 |
| #TS | Invalid TSS | Fault | TSS 세그먼트 선택자 오류 |
| #NP | Segment Not Present | Fault | 존재하지 않는 세그먼트 접근 |
| #SS | Stack Segment Fault | Fault | 스택 세그먼트 오류 |
| #GP | General Protection Fault | Fault | 일반 보호 오류 (메모리/세그먼트 위반) |
| #PF | Page Fault | Fault | 페이지 디렉토리/테이블 항목 없음 |
| #MF | x87 FPU Error | Fault | x87 부동소수점 오류 |
| #AC | Alignment Check | Fault | 비정렬 메모리 접근 |
| #MC | Machine Check | Abort | 하드웨어 오류 |
| #XM | SIMD Exception | Fault | SSE/SSE2 부동소수점 예외 |
동작 원리
인터럽트 처리 흐름
하드웨어 인터럽트가 발생했을 때의 전체 처리 과정:
- 인터럽트 인식: 프로세서가 현재 명령어 실행 완료 후 인터럽트 라인 확인
- 컨텍스트 저장: 현재 프로세서 상태 (RIP, RFLAGS, CS, SS 등)를 스택에 저장
- 인터럽트 컨트롤러 응답: PIC/APIC에 인터럽트 확인(ACK) 전송
- 핸들러 조회: IDT에서 해당 벡터 번호의 핸들러 주소 로드
- 컨텍스트 스위치: 핸들러의 스택으로 전환 (IST 사용 시)
- 핸들러 실행: ISR(Interrupt Service Routine) 실행
- 상태 복원: 저장된 프로세서 상태를 스택에서 복원
- IRET 실행: 인터럽트 처리 완료, 원래 프로그램으로 복귀
인터럽트 처리 흐름:
┌──────────────┐
│ 현재 명령어 │
│ 실행 완료 │
└──────┬───────┘
▼
┌──────────────┐ ┌──────────────┐
│ 인터럽트 │ Yes │ 인터럽트 │
│ 라인 확인 ──┼────►│ 활성화? │
└──────┬───────┘ └──────┬───────┘
│ No │ Yes
▼ ▼
┌──────────────┐ ┌──────────────┐
│ 다음 명령어 │ │ 상태 저장 │
│ 실행 │ │ (스택에) │
└──────────────┘ └──────┬───────┘
▼
┌──────────────┐
│ IDT에서 │
│ 핸들러 주소 │
│ 조회 │
└──────┬───────┘
▼
┌──────────────┐
│ ISR 실행 │
└──────┬───────┘
▼
┌──────────────┐
│ IRET 실행 │
│ 복귀 │
└──────────────┘
인터럽트 컨트롤러 (PIC/APIC)
현대 x86 시스템에서는 APIC(Advanced Programmable Interrupt Controller)를 사용한다:
- 로컬 APIC (LAPIC): 각 CPU 코어에 탑재, 인터럽트 우선순위 처리, IPI(Inter-Processor Interrupt) 전송
- I/O APIC: 외부 디바이스의 인터럽트를 시스템 버스로 전달, IRQ 라우팅 및 우선순위 설정
- MSI/MSI-X (Message Signaled Interrupts): 메모리 쓰기 명령어로 인터럽트 전송, PCIe 디바이스에서 사용
APIC 인터럽트 전달 경로:
┌──────────────┐
│ 외부 디바이스 │
└──────┬───────┘
▼
┌──────────────┐
│ I/O APIC │ IRQ 라우팅, 우선순위 설정
└──────┬───────┘
▼
┌──────────────┐
│ 시스템 버스 │
└──────┬───────┘
▼
┌──────────────┐ ┌──────────────┐
│ 로컬 APIC │────►│ CPU 코어 0 │
└──────────────┘ └──────────────┘
│
▼
┌──────────────┐ ┌──────────────┐
│ 로컬 APIC │────►│ CPU 코어 1 │
└──────────────┘ └──────────────┘
스택 스위칭 메커니즘
인터럽트 발생 시 스택 전환이 중요한 이유:
- 안전성: 사용자 스택의 오버플로우가 커널 스택에 영향을 주지 않도록 격리
- 중첩 인터럽트 처리: 여러 인터럽트가 동시에 발생할 경우 스택 공간 확보
- IST (Interrupt Stack Table): x86-64에서 특정 인터럽트용 고정 스택 할당 가능
- IST 엔트리 1: Double Fault 핸들러용
- IST 엔트리 2: NMI 핸들러용
- IST 엔트리 3: Machine Check 핸들러용
인터럽트 지연 시간 (Interrupt Latency)
인터럽트 지연 시간은 인터럽트 신호가 발생한 시점부터 ISR의 첫 명령어가 실행되기까지의 시간을 의미한다. 주요 구성 요소는 다음과 같다:
| 지연 요소 | 설명 | 영향 요인 |
|---|---|---|
| 하드웨어 지연 | 인터럽트 컨트롤러(PIC/APIC)의 신호 전파 및 동기화 시간 | 컨트롤러 종류, 버스 속도 |
| 명령어 완료 대기 | 현재 실행 중인 명령어가 완료될 때까지 대기 | 명령어 복잡도 (특히 긴 문자열 연산) |
| 인터럽트 마스킹 | CLI 등으로 인터럽트가 비활성화된 구간 | 크리티컬 섹션 길이 |
| 컨텍스트 저장 | 레지스터, 스택 포인터 등 프로세서 상태 저장 | 저장할 레지스터 개수 |
| 벡터 테이블 조회 | IDT/VBAR에서 핸들러 주소 로드 | 캐시 히트 여부 |
실시간 시스템에서는 인터럽트 지연 시간이 최악 실행 시간(WCET) 분석의 핵심 요소이며, ARM의 FIQ(Fast Interrupt Request)는 전용 레지스터 뱅크를 통해 컨텍스트 저장 오버헤드를 줄여 지연 시간을 최소화한다.
소프트웨어 인터럽트 (시스템 호출)
시스템 호출은 소프트웨어 인터럽트의 대표적인 예:
시스템 호출 흐름:
┌──────────────┐
│ 사용자 모드 │ 응용 프로그램
│ │ SYSCALL 명령어 실행
└──────┬───────┘
▼
┌──────────────┐
│ 커널 모드 │ 커널 진입
│ │ 시스템 호출 번호 확인
└──────┬───────┘
▼
┌──────────────┐
│ 시스템 호출 │ 커널 핸들러 실행
│ 테이블 조회 │
└──────┬───────┘
▼
┌──────────────┐
│ 커널 핸들러 │ 실제 작업 수행
│ 실행 │
└──────┬───────┘
▼
┌──────────────┐
│ 사용자 모드 │ 결과 반환
│ 복귀 │
└──────────────┘
장단점
인터럽트 기반 I/O의 장점
- CPU 효율성: 디바이스가 준비될 때까지 CPU가 대기하지 않음 (폴링 대비)
- 지연 시간 최소화: 이벤트 발생 즉시 처리 가능
- 동시성 지원: 여러 디바이스의 요청을 독립적으로 처리
- 멀티태스킹 기반: 타이머 인터럽트로 프로세스 스케줄링 구현
- 에너지 절약: 유휴 시 인터럽트 대기로 전력 소비 감소
인터럽트 기반 I/O의 단점
- 컨텍스트 스위치 오버헤드: 상태 저장/복원에 시간 소요
- 인터럽트 스톰: 과도한 인터럽트 발생 시 시스템 성능 저하
- 동기화 문제: 공유 자원에 대한 경쟁 조건 발생 가능
- 디버깅 난이도: 비동기적으로 발생하여 재현 어려움
- 스택 오버플로우 위험: 중첩 인터럽트 시 스택 공간 부족 가능
- 인터럽트 스톰 (Interrupt Storm): 과도한 인터럽트 발생률로 인해 CPU가 인터럽트 처리에만 몰두하여 일반 작업을 전혀 수행하지 못하는 현상. 높은 네트워크 트래픽 환경에서 특히 문제가 된다.
- 라이브락 (Livelock): 인터럽트 처리가 전체 시스템 시간을 소비하여 다른 필수 작업이 배제되는 상태. 수신 라이브락(receive livelock)은 네트워크 인터럽트가 과도하게 발생할 때 운영체제가 패킷 처리를 위한 사용자 프로세스 스케줄링을 하지 못하는 현상이다.
인터럽트 핸들러 설계 시 주의사항
- 최소한의 작업만 수행: 빠른 반환을 위해 무거운 작업은 백그라운드 처리
- 스핀락 사용 지양: 인터럽트 핸들러 내에서 뮤텍스/세마포어 사용 금지
- NMI 핸들러 보수적 설계: 다른 인터럽트와 격리된 환경에서 동작
- 스택 사용량 최소화: 중첩 인터럽트 대비 충분한 스택 공간 확보
- 인터럽트 소스 확인: 스페어 인터럽트 처리를 위해 반드시 원인 확인
관련 기술
관련 하드웨어 기술
| 기술 | 설명 | 관련 인터럽트 |
|---|---|---|
| APIC (Advanced Programmable Interrupt Controller) | x86 멀티프로세서 인터럽트 관리 | IRQ, IPI |
| GIC (Generic Interrupt Controller) | ARM 아키텍처 인터럽트 관리 | IRQ, FIQ, SError |
| MSI/MSI-X (Message Signaled Interrupts) | PCIe 디바이스 인터럽트 메커니즘 | 메모리 쓰기 기반 인터럽트 |
| NMI (Non-Maskable Interrupt) | 비마스크 인터럽트, 하드웨어 오류 등 | 시스템 오류, 전원 상실 |
| IPI (Inter-Processor Interrupt) | 프로세서 간 인터럽트 | 멀티코어 동기화, 컨텍스트 스위칭 |
관련 소프트웨어 기술
| 기술 | 설명 | 관련 인터럽트 |
|---|---|---|
| ISR (Interrupt Service Routine) | 인터럽트 처리 루틴 | 모든 인터럽트 처리 |
| IDT (Interrupt Descriptor Table) | x86 인터럽트 벡터 테이블 | 벡터별 핸들러 주소 관리 |
| IRQ Affinity | 인터럽트를 특정 CPU 코어에 바인딩 | 로드 밸런싱, 성능 최적화 |
| Bottom Half (Linux) | ISR에서 지연된 처리를 위해 사용자 스케줄링 | 무거운 ISR 작업 분할 |
| Deferred Procedure Call (Windows) | ISR에서 지연된 처리 실행 | 윈도우 커널 인터럽트 처리 |
| Interrupt Coalescing | 여러 인터럽트를 하나로 묶어 일괄 처리 | 네트워크 카드, 스토리지 컨트롤러 |
| RSS (Receive-Side Scaling) | NIC의 멀티큐를 활용해 인터럽트를 여러 코어로 분산 | 네트워크 인터럽트 부하 분산 |
| RPS (Receive Packet Steering) | 소프트웨어 기반 수신 패킷 분산 (ISR 내 처리) | RSS 미지원 NIC에서 부하 분산 |
참고 문헌
- Intel Corporation. Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 3A: System Programming Guide. Chapter 6: Interrupt and Exception Handling.
- ARM Limited. ARM Architecture Reference Manual for A-profile Architecture. Chapter D1: Exception Model.
- Corbet, J., Rubini, A., Kroah-Hartman, G. Linux Device Drivers, 3rd Edition. O'Reilly Media, 2005. Chapter 10: Interrupt Handling.
- Tanenbaum, A.S., Bos, H. Modern Operating Systems, 5th Edition. Pearson, 2022. Chapter 3: Memory Management.
- Hennessy, J.L., Patterson, D.A. Computer Architecture: A Quantitative Approach, 6th Edition. Morgan Kaufmann, 2019.
- Intel Corporation. Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 2: Instruction Set Reference. Chapter 3-4: System Instructions.
핵심 정리
-
인터럽트와 예외는 프로세서가 현재 실행을 중단하고 특수 처리 루틴으로 전환하는 메커니즘으로, 현대 컴퓨터 시스템의 동작 기반이다. 인터럽트는 외부 디바이스의 비동기 이벤트를, 예외는 프로세서 내부의 동기적 오류를 처리한다.
-
x86 아키텍처에서는 IDT(Interrupt Descriptor Table)를 통해 256개의 인터럽트 벡터를 관리하며, 각 벡터는 고유한 핸들러 주소를 가진다. ARM에서는 VBAR_ELx 레지스터를 사용하여 벡터 테이블을 관리한다.
-
인터럽트 컨트롤러(PIC/APIC, GIC)는 여러 디바이스의 인터럽트를 우선순위에 따라 프로세서에 전달하며, 현대 시스템에서는 MSI/MSI-X를 통해 PCIe 디바이스의 인터럽트를 효율적으로 처리한다.
-
인터럽트 핸들러(ISR)는 최소한의 작업만 수행하고, 무거운 처리는 백그라운드(Bottom Half/Deferred Procedure Call)로 위임하는 것이 바람직하다. 이는 인터럽트 스톰과 지연 시간을 방지하는 핵심 설계 원칙이다.
-
인터럽트 트리거 방식(레벨 트리거 vs 엣지 트리거)은 디바이스 공유와 누락 위험 사이의 트레이드오프를 결정하며, 시스템 요구사항에 따라 적절히 선택해야 한다.
-
스퓨리어스 인터럽트와 인터럽트 누락은 각각 wired-OR 회로의 기생 커패시턴스와 마스킹 구간의 이벤트 손실에서 비롯되며, ISR의 방어적 설계와 하드웨어 상태 레지스터로 대응한다. 인터럽트 통합(Coalescing)과 RSS/RPS는 높은 인터럽트 부하 환경에서 CPU 효율을 유지하는 핵심 기법이다.