개요
프로그래밍을 하다보면, 가끔 인터럽트(Interrupt)라는 용어가 등장합니다. 이 글에선 인터럽트가 무엇이며, 어떻게 동작하는지 알아보겠습니다.
인터럽트
인터럽트는 명령어 사이클 중에 발생하는데, CPU가 급하게 처리해야 하는 일이 생겼을 때, 현재 작업을 중단하고 다른 작업을 처리하고자 할 때 발생합니다.
명령어 사이클
CPU가 명령어를 실행하는 과정을 명령어 사이클이라고 합니다.
1 2 3 4 5 6 7 8 9 |-------------| /--> | Fetch Cycle | -->\ / |-------------| \ |-----------------| ^ | |----------------| | Interrupt Cycle | | | | Indirect Cycle | |-----------------| | v |----------------| \ |---------------| / \<-- | Execute Cycle | <--/ |---------------|Fetch Cycle (인출 사이클)는 명령어를 읽어오는 과정이며 (
fetch
), Execute Cycle (실행 사이클)은 명령어를 해독하고 실행하는 과정입니다. (decode
,execute
) 이 두 과정이 기본 사이클이며, 명령어를 실행중에 메모리 접근이 추가적으로 필요할 경우 Indirect Cycle (간접 사이클)이 추가됩니다.여기에 후술할 인터럽트가 발생한다면, Interrupt Cycle (인터럽트 사이클)이 추가됩니다.
인터럽트는 크게 동기 인터럽트와 비동기 인터럽트로 나뉩니다.
동기 인터럽트
예외라고도 불리며, 명령어를 실행하는 과정에서 발생하는 인터럽트입니다. 예를 들어 0으로 나누는 연산을 수행하려고 할 때(Division by Zero), 동기 인터럽트가 발생합니다.
이때 폴트(Fault), 트랩(Trap), 중단(Abort), 소프트웨어 인터럽트 등으로 나뉩니다.
- 폴트(Fault): 잘못된 명령어나 데이터 접근 등의 오류로 인해 발생합니다. 이 경우 예외 처리를 통해 방지할 수 있습니다.
- 트랩(Trap): 의도적으로 발생시키는 인터럽트입니다. 예를 들어, 디버깅을 위해 의도적으로 트랩을 발생시킬 수 있습니다.
- 중단(Abort): 프로그램을 강제로 종료시키는 인터럽트입니다.
- 소프트웨어 인터럽트: 프로그램이 명시적으로 요청한 인터럽트입니다. 예를 들어, 시스템 콜 등이 있습니다.
비동기 인터럽트
하드웨어 인터럽트로도 불리며, 주로 입출력 장치 등의 외부 장치에 의해 인터럽트입니다.
키보드로 예를 들면, 어떠한 키를 눌렀을 때, 키보드가 CPU에게 인터럽트를 발생시킵니다. 다른 예로, 프린터가 출력을 완료했을 때, 프린터가 CPU에게 인터럽트를 발생시킵니다.
프린터기는 CPU의 처리 속도에 비해 훨씬 느리기 때문에, 프린터가 출력을 완료했을 때 CPU가 프린터의 출력을 기다리는 것은 비효율적입니다.
그렇기에, 인터럽트를 통해 효율적으로 작업을 처리할 수 있습니다. 만약 인터럽트가 없다면, 주기적으로 확인하는 등의 방법으로 작업을 처리해야 합니다.
인터럽트 처리
인터럽트는 주로 아래와 같은 순서로 처리됩니다.
- CPU에게 인터럽트 요청 신호를 보냅니다.
- CPU는 하나의 명령어 사이클이 끝나고, 명령어를 인출하기 전에 인터럽트 요청 신호를 확인합니다.
- 만약 인터럽트 요청이 확인됐다면, 인터럽트 플래그 레지스터를 통해 인터럽트를 받아들일지 말지 결정합니다.
- 만약 인터럽트를 받아들일 수 있다면, 지금까지의 작업을 스택에 백업하고, 인터럽트 벡터를 참조하여 인터럽트 서비스 루틴을 실행합니다.
- 인터럽트 서비스 루틴이 끝나면, 백업한 작업을 복구하고 다시 실행합니다.
인터럽트 요청 신호, 인터럽트 플래그
인터럽트 요청 신호는, 이름 그대로 인터럽트를 요청하는 신호입니다.
CPU가 인터럽트 요청을 받아들이기 위해선, 플래그 레지스터 중 하나인 인터럽트 플래그에서 인터럽트를 받아들일 수 있다고 해야 인터럽트를 받아들일 수 있습니다.
다만, 일부 인터럽트는 인터럽트 플래그를 무시하고 실행될 수 있습니다.
인터럽트 서비스 루틴, 인터럽트 벡터
인터럽트 서비스 루틴은 인터럽트가 발생했을 때, 해당 인터럽트를 어떻게 처리해야 될지 정의한 코드입니다. 인터럽트 서비스 루틴 또한 하나의 프로그램이기 때문에, 메모리에 저장되어 있습니다.
만약 어떠한 인터럽트가 발생했을 때, 인터럽트 서비스 루틴을 실행하기 위해 jump
를 통해 해당 메모리 지점으로 이동해야 하는데, 이러한 인터럽트 서비스 루틴를 구분하기 위한것이 인터럽트 벡터입니다.