맨위로가기

인터럽트 핸들러

"오늘의AI위키"는 AI 기술로 일관성 있고 체계적인 최신 지식을 제공하는 혁신 플랫폼입니다.
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.

1. 개요

인터럽트 핸들러는 컴퓨터 시스템에서 인터럽트 발생 시 해당 인터럽트를 처리하는 코드이다. 인터럽트는 하드웨어 또는 소프트웨어에 의해 발생하며, CPU는 인터럽트 벡터 테이블을 참조하여 해당 인터럽트를 처리하는 핸들러의 주소로 이동한다. 인터럽트 핸들러는 인터럽트의 원인을 파악하고 필요한 작업을 수행한 후, 인터럽트 복귀 명령어를 사용하여 이전 작업으로 복귀한다. 현대 운영체제에서는 인터럽트 핸들러를 FLIH와 SLIH로 나누어 지터 감소와 시스템 안정성을 확보한다. 인터럽트 핸들러 설계 시 시간 및 동시성 제약, 스택 오버플로우 방지, 재진입성, 인터럽트 플래그 설정, 스케줄링 등을 고려해야 한다.

더 읽어볼만한 페이지

  • 인터럽트 - 프로그래머블 인터럽트 컨트롤러
    프로그래머블 인터럽트 컨트롤러(PIC)는 컴퓨터 시스템에서 인터럽트 요청을 관리하며, 인터럽트 요청 레지스터 등을 사용하여 인터럽트를 처리하고 다양한 우선순위 체계를 지원하며, x86 아키텍처에서는 인텔 8259가 널리 사용되었다.
  • 인터럽트 - 도스 API
    도스 API는 응용 프로그램이 MS-DOS 운영체제의 시스템 기능을 사용하도록 제공되는 인터페이스로, CP/M 호환성을 고려한 초기 설계 이후 유닉스 개념 도입, 네트워크 기능 추가 등으로 확장되었으며, 다양한 운영체제에서 에뮬레이터를 통해 지원된다.
  • 마이크로컨트롤러 - 마이크로프로세서
    마이크로프로세서는 CPU 기능을 단일 IC에 통합한 것으로, 무어의 법칙에 따라 성능이 향상되어 왔으며 다양한 아키텍처와 기술 발전을 거쳐 현재 광범위한 분야에서 사용된다.
  • 마이크로컨트롤러 - ARM 아키텍처
    ARM 아키텍처는 저전력 설계로 모바일 기기에서 널리 쓰이는 RISC 기반 프로세서 아키텍처로서, IP 코어 라이선스 모델과 ARM Flexible Access를 통해 다양한 분야로 확장되고 있다.
  • 컴퓨터 구조 - PA-RISC
    PA-RISC는 휴렛 팩커드에서 개발한 RISC 기반 명령어 집합 아키텍처로, HP 서버 및 워크스테이션에 사용되었으며 대용량 L1 캐시와 SIMD 명령어 확장 등의 특징을 가졌으나 아이테니엄 아키텍처로의 전환으로 단종되었다.
  • 컴퓨터 구조 - 메모리 관리
    메모리 관리는 운영체제의 핵심 기능으로, 여러 프로세스의 원활한 실행을 위해 메모리 공간을 할당하고 관리하며, 릴로케이션, 보호, 공유, 가상 메모리 관리, 자동/수동 메모리 관리 등의 기능을 수행한다.
인터럽트 핸들러

2. 인터럽트 발생 원인

컴퓨터 시스템에서 인터럽트는 다양한 원인에 의해 발생할 수 있다. 인터럽트 발생 원인은 크게 하드웨어 인터럽트와 소프트웨어 인터럽트로 나눌 수 있다.


  • 하드웨어 인터럽트
  • 하드웨어 RESET
  • 정해진 메모리 밖의 엑세스
  • 0으로 나누기
  • 컴퓨터 시스템의 기능 장치(타이머, UART, SPI, I2C, USB, 이더넷 등)
  • 소프트웨어 인터럽트 (x86의 INT xxH 명령어)

2. 1. 하드웨어 인터럽트

컴퓨터는 여러 입출력 장치를 통해 작동하며, 대부분의 장치는 인터럽트를 지원한다. 각 장치는 특정 기능을 수행하며, 인터럽트 핸들러를 통해 이에 대응한다.

  • 하드웨어 RESET
  • 정해진 메모리 범위를 벗어나는 접근
  • 0으로 나누기
  • 컴퓨터 시스템의 기능 장치로부터 발생하는 인터럽트
  • 타이머
  • UART
  • SPI, I2C
  • USB
  • 이더넷
  • 기타 장치
[1]

2. 2. 소프트웨어 인터럽트

운영체제 서비스를 요청하기 위해 시스템 호출이 발생한다. (x86의 INT xxH 명령어)[1]

3. 인터럽트 핸들러의 작동 방식

인터럽트가 발생하면 CPU는 현재 실행 중인 작업을 중단하고 인터럽트 벡터 테이블을 참조하여 해당 인터럽트를 처리하는 핸들러의 주소로 이동한다. 인터럽트 핸들러는 인터럽트의 원인을 파악하고 필요한 작업을 수행한다. 인터럽트 처리 완료 후, 핸들러는 인터럽트 복귀 명령어(IRET)를 사용하여 중단되었던 이전 작업으로 복귀한다.

인터럽트 핸들러는 실행 중인 프로세스의 메모리 및 실행 컨텍스트에서 시작되며, 이는 특별한 연결이 없다. 인터럽트는 본질적으로 실행 컨텍스트를 빼앗는 것이며, 프로세스 시간 회계는 종종 인터럽트 처리에 소요된 시간을 인터럽트된 프로세스에 누적시킨다.[1]

인터럽트 핸들러는 제한된 스택 공간을 사용하므로, 스택 오버플로우가 발생하지 않도록 주의해야 한다. 낮은 수준의 마이크로컨트롤러에서는 칩에 보호 모드가 없고 메모리 관리 유닛(MMU)이 없을 수 있다. 이러한 칩에서 인터럽트 핸들러는 일반적으로 고정 크기의 작은 스택에서 실행되며, 중첩 인터럽트가 제공되는 경우 스택 사용량이 더 늘어날 수 있다. 다중 태스킹 시스템에서 각 실행 스레드는 자체 스택을 가지며, 인터럽트는 인터럽트된 스레드의 스택 공간을 사용한다.

3. 1. 인터럽트 플래그

인터럽트 핸들러는 인터럽트 플래그를 적절한 값으로 설정해야 하는 핵심 기능을 수행한다.[1]

중첩 인터럽트를 지원하는 CPU에서, 핸들러는 종종 모든 인터럽트가 전역적으로 마스킹된 상태로 실행된다.[1] 이러한 아키텍처에서 인터럽트 핸들러는 일반적으로 필요한 최소한의 컨텍스트를 저장한 다음, 가능한 한 빨리 전역 인터럽트 비활성화 플래그를 재설정하여 우선순위가 더 높은 인터럽트가 현재 핸들러를 중단할 수 있도록 허용한다.[1] 또한, 인터럽트 핸들러는 (주변 장치 레지스터의 플래그 비트를 토글하는 등의 방법으로) 현재 인터럽트 소스를 억제하여 핸들러 종료 시 현재 인터럽트가 즉시 반복되어 무한 루프가 발생하는 것을 방지해야 한다.[1]

3. 2. 실행 컨텍스트

성능상의 이유로, 인터럽트 핸들러는 일반적으로 실행 중인 프로세스의 메모리 및 실행 컨텍스트에서 시작되며, 이는 특별한 연결이 없다. 인터럽트는 본질적으로 실행 컨텍스트를 빼앗는 것이며, 프로세스 시간 회계는 종종 인터럽트 처리에 소요된 시간을 인터럽트된 프로세스에 누적시킨다.[1] 그러나 인터럽트된 프로세스와 달리, 인터럽트는 일반적으로 하드 코딩된 CPU 메커니즘에 의해 하드웨어 리소스에 직접 접근할 수 있을 정도로 높은 권한 수준으로 승격된다.[1]

3. 3. 스택 공간 고려 사항

인터럽트 핸들러는 제한된 스택 공간을 사용하므로, 스택 오버플로우가 발생하지 않도록 주의해야 한다. 낮은 수준의 마이크로컨트롤러에서는 칩에 보호 모드가 없고 메모리 관리 유닛(MMU)이 없을 수 있다. 이러한 칩에서 인터럽트 핸들러는 일반적으로 고정 크기의 작은 스택에서 실행되며, 중첩된 인터럽트가 제공되는 경우 스택 사용량이 더 늘어날 수 있다. 할당된 스택 공간을 초과하면 하드웨어에서 이를 감지하지 못하고, 메모리 손상으로 인해 애플리케이션이 나중에 실패할 수 있다. 쓰기 불가능한 메모리 영역으로 스택이 초과되면 핸들러 자체 내에서 오류가 발생한다.

쓰기 가능한 경우, 스택 끝에 감시 스택 가드를 구현하여 스택 오버플로우를 조기에 감지할 수 있다. 다중 태스킹 시스템에서 각 실행 스레드는 자체 스택을 가지며, 인터럽트는 인터럽트된 스레드의 스택 공간을 사용한다. 사용자 스택은 스택 오버플로우가 MMU에 의해 시스템 오류로 포착되도록 구성된다.

높은 스레드 수를 지원하는 시스템에서는 하드웨어 인터럽트 메커니즘이 스택을 특수 시스템 스택으로 전환하는 것이 좋다. 이렇게 하면 스레드 스택이 최악의 경우 중첩된 인터럽트 사용을 고려할 필요가 없다. 예를 들어, 8비트 모토로라 6809 CPU는 별도의 시스템 및 사용자 스택 포인터를 제공했다.

4. 인터럽트 핸들러의 구현

인터럽트 핸들러는 주로 어셈블리어나 C 언어와 같은 저수준 언어로 작성된다. x86 아키텍처에서는 `INT` 명령어를 사용하여 소프트웨어 인터럽트를 발생시킬 수 있다.[1]

4. 1. x86 인터럽트 핸들러 (예시)

대개 16비트(실제 주소 모드라고도 함)에서 실행되며, 인터럽트 명령어는 윈도우 NT 미만 버전에서 실행되어야 한다. 윈도우 NT부터는 에뮬레이터 모드로 실행되어 하드웨어에 직접 접근할 수 없으며 윈도우 비스타부터는 제3자 에뮬레이터가 없으면 실행이 불가능하다.[1]

어셈블리어로 이루어진 코드에서 (MASM 기준으로) `int (번호)`를 사용한 호출이 가능하다. 예를 들면 다음처럼 쓸 수 있다.[1]

```asm

.data

welcome_message BYTE 'Welcome! interrupt call 21h.', 0dh, 0ah

.code

mov ah, 40h

mov bx, 1

mov cx, lengthof welcome_message

mov dl, offset welcome_message

int 21h ; << 인터럽트 호출 Interrupt call.

```

00000~003FF 까지가 CPU가 인터럽트를 처리할 때 사용하는 메모리 주소이다. (32비트 주소 테이블, 인터럽트 벡터 테이블)

만약 다음 코드가 있다면,[1]

```asm

mov ah, 2

mov dl, 'P'

int 21h ; << 1

push al

```

`<< 1` 표시를 한 줄에서는 인터럽트 벡터 테이블에서 명령어를 호출한다.[1]

```asm

sti

;.....COMMANDS.....

IRET ; << 2

```

`<< 2` 표시를 한 줄에서 다시 돌아와 `<< 1` 표시를 한곳으로 와서 `push al`이 수행된다.[1]

5. 현대 운영체제에서의 인터럽트 핸들러

현대 운영 체제에서는 인터럽트 핸들러를 제1수준 인터럽트 핸들러(FLIH)와 제2수준 인터럽트 핸들러(SLIH) 두 부분으로 나눈다. FLIH는 '하드 인터럽트 핸들러' 또는 '빠른 인터럽트 핸들러'라고도 하며, SLIH는 '느린/소프트 인터럽트 핸들러' 또는 윈도우의 지연 프로시저 호출이라고도 한다.[2]

FLIH는 플랫폼별 최소한의 인터럽트 처리를 구현한다. 인터럽트 발생 시 컨텍스트 스위칭이 발생하고 FLIH가 실행된다. FLIH는 인터럽트를 빠르게 처리하거나, 인터럽트 시점에만 얻을 수 있는 중요 정보를 기록하고, 시간이 오래 걸리는 처리를 위해 SLIH 실행을 스케줄링한다.

FLIH는 프로세스 실행에 지터를 유발하고 인터럽트를 마스킹한다. 실시간 운영 체제에서는 지터 감소가 중요하므로, FLIH 실행 시간을 최소화하고 가능한 많은 처리를 SLIH로 이관한다. 하드웨어를 처리하는 FLIH는 보통 실행 완료까지 관련 인터럽트를 마스킹한다. 실행 완료 전에 관련 인터럽트를 언마스크하는 FLIH는 재진입 인터럽트 핸들러라고 하며, 스택 오버플로우를 유발할 수 있어 일반적으로 사용하지 않는다. 인터럽트 우선 순위 시스템에서 FLIH는 동일하거나 낮은 우선 순위의 다른 인터럽트도 마스킹한다.

SLIH는 프로세스와 같이 시간이 오래 걸리는 인터럽트 처리를 수행한다. 각 핸들러에 대한 전용 커널 스레드를 갖거나 커널 작업자 스레드 풀에 의해 실행된다. 이 스레드들은 운영 체제의 실행 큐에 대기하며, 프로세서 시간을 사용할 수 있을 때 인터럽트 처리를 수행한다.

리눅스에서 FLIH는 '상위 반', SLIH는 '하위 반' 또는 '하단 반'이라고 부른다.[1][2]

5. 1. 제1수준 인터럽트 핸들러 (FLIH)

제1수준 인터럽트 핸들러(FLIH)는 '하드 인터럽트 핸들러' 또는 '빠른 인터럽트 핸들러'라고도 불리며, 인터럽트 발생 시 즉시 실행되는 짧은 루틴이다.[2] 인터럽트가 발생하면 컨텍스트 스위칭이 발생하고 FLIH가 실행된다. FLIH의 주요 역할은 다음과 같다.

  • 인터럽트 신속 처리: 인터럽트를 빠르게 처리하거나, 인터럽트 시점에만 얻을 수 있는 플랫폼별 중요 정보를 기록한다.
  • SLIH 스케줄링: 추가적인 장기 인터럽트 처리를 위해 제2수준 인터럽트 핸들러(SLIH)의 실행을 스케줄링한다.[2]


FLIH는 프로세스 실행에 지터를 유발하고 인터럽트를 마스킹한다. 실시간 운영 체제에서는 지터 감소가 중요하므로, FLIH의 실행 시간을 최소화하고 가능한 많은 처리를 SLIH로 이관한다.

하드웨어를 처리하는 FLIH는 일반적으로 실행 완료 시까지 관련 인터럽트를 마스킹(또는 마스킹된 상태로 유지)한다. 실행 완료 전에 관련 인터럽트를 언마스크하는 FLIH는 재진입 인터럽트 핸들러라고 하는데, 스택 오버플로우를 유발할 수 있으므로 일반적으로 사용하지 않는다. 인터럽트 우선 순위 시스템에서 FLIH는 동일하거나 낮은 우선 순위의 다른 인터럽트도 (잠시 동안) 마스킹한다.

최근 컴퓨터에서는 FLIH가 모든 장치 및 플랫폼 종속 처리를 구현하고, SLIH를 사용하여 추가적인 플랫폼 독립적 장기 처리를 수행하기도 한다.

5. 2. 제2수준 인터럽트 핸들러 (SLIH)

제2수준 인터럽트 핸들러(SLIH)는 느린/소프트 인터럽트 핸들러 또는 지연 프로시저 호출(윈도우)이라고도 불린다.[2] SLIH는 FLIH에 의해 스케줄링되며, 시간이 오래 걸리는 인터럽트 처리 작업을 수행한다.[2] SLIH는 각 핸들러에 대한 전용 커널 스레드를 갖거나 커널 작업자 스레드 풀에 의해 실행될 수 있다. 이러한 스레드는 운영 체제의 실행 큐에서 대기하며, 프로세서 시간을 사용할 수 있을 때 인터럽트 처리를 수행한다. SLIH는 장기간 실행될 수 있으므로, 일반적인 스레드 및 프로세스와 유사하게 스케줄링된다.

리눅스에서 FLIH는 '상위 반', SLIH는 '하위 반' 또는 '하단 반'이라고 부른다.[1][2]

5. 3. 인터럽트 스레드 (솔라리스, macOS, FreeBSD 등)

솔라리스, macOS, FreeBSD 등과 같은 운영체제에서는 인터럽트 스레드(Interrupt thread영어)라고 불리는 방식을 채용하고 있다. 인터럽트 핸들러는 높은 우선순위를 가진 스레드이며, 인터럽트에 의해 기동되고, 상호 배제로 블록되는 중요한 특징이 있다. 이것으로 인해 커널 내의 기구가 대폭 단순화된다. 또한 인터럽트 스레드는 더 높은 우선순위를 가진 인터럽트 스레드에 의해 선점된다.[3]

인터럽트 스레드를 사용하면, 인터럽트 핸들러의 대부분을 제한이 많은 재진입 구현이나 인터럽트 자체의 마스크 없이, 제한이 더 완화되고 병렬도가 높은 스레드 안전만 확보된 조건에서 구현할 수 있다. 인터럽트 스레드를 사용하지 않는 경우, 인터럽트된 처리는 인터럽트 핸들러의 처리가 종료될 때까지 전혀 실행할 수 없기 때문에, 인터럽트 핸들러가 재진입 불가능하면 예기치 않은 동작을 하게 된다. 인터럽트 스레드를 도입하면 인터럽트 핸들러의 처리가 스케줄링의 대상이 되므로, 인터럽트 스레드 전체에 대한 재진입성은 (스레드로서는 절대로 구현할 수 없는 인터럽트 스레드의 기동 처리를 제외하고) 필요 없어진다.

인터럽트 스레드가 본래의 인터럽트 처리에 가까운 동작을 하기 위해서는 단순히 스레드로서의 구현뿐만 아니라, 특히 커널 내에서 인터럽트용이 아닌 스레드를 인터럽트 스레드가 선점하는 것이 필요하다.

6. 인터럽트 핸들러 설계 시 고려 사항

인터럽트 핸들러 설계 시 고려해야 할 사항은 다음과 같다.


  • 시간 및 동시성 제약: 인터럽트 핸들러는 가능한 짧게 실행해야 하며, 하드웨어 인터럽트가 차단될 수 있는 시스템 호출은 피해야 한다.[1] 다중 실행 코어 시스템에서는 재진입성을 고려해야 하고, DMA 사용 시스템에서는 단일 CPU 코어만으로도 동시성 문제가 발생할 수 있다.[1]

  • 스택 오버플로우 방지: 메모리 관리 유닛(MMU)이 없는 마이크로컨트롤러에서는 인터럽트 핸들러가 작은 스택에서 실행되므로 스택 오버플로우가 발생하기 쉽다. 스택 가드를 구현하여 이를 감지할 수 있다.[1] 다중 태스킹 시스템에서 인터럽트는 인터럽트된 스레드의 스택 공간을 사용하며, MMU를 통해 스택 오버플로우를 감지하고 처리할 수 있다.

  • 인터럽트 핸들러 검증: 인터럽트 핸들러의 오류는 시스템을 멈추게 하는 심각한 버그를 유발할 수 있으며,[1] 간헐적으로 발생하여 발견 및 검증이 매우 어렵다.[1]

6. 1. 시간 및 동시성 제약

인터럽트 핸들러는 가능한 한 짧게 실행되어야 하며, 하드웨어 인터럽트가 차단될 수 있는 시스템 호출을 하는 것은 권장되지 않거나 금지된다.[1] 여러 실행 코어를 가진 시스템에서는 재진입성을 고려해야 한다.[1] DMA를 제공하는 시스템에서는 단일 CPU 코어만으로도 동시성 문제가 발생할 수 있다.[1] 중급 마이크로컨트롤러 중에는 보호 수준과 MMU는 없지만, 많은 채널을 가진 DMA 엔진을 제공하는 경우가 있다.[1] 이러한 경우, 많은 인터럽트가 DMA 엔진 자체에 의해 트리거되므로, 관련 인터럽트 핸들러를 주의해서 처리해야 한다.[1]

6. 2. 스택 오버플로우 방지

메모리 관리 유닛(MMU)이 없는 낮은 수준의 마이크로컨트롤러에서는 인터럽트 핸들러가 고정 크기의 작은 스택에서 실행되므로 스택 오버플로우가 발생하기 쉽다. 스택 오버플로우는 하드웨어에서 감지되지 않아 메모리 손상 및 애플리케이션 오류를 유발할 수 있다. 이를 방지하기 위해 스택 가드를 구현하여 스택 끝에 고정 값을 설정하고, 이 값이 변경되는지 감시하여 스택 오버플로우를 감지할 수 있다.[1]

다중 태스킹 시스템에서는 각 스레드가 자체 스택을 가지며, 인터럽트는 인터럽트된 스레드의 스택 공간을 사용한다. MMU를 통해 스택 오버플로우를 감지하고 시스템 오류로 처리하거나 메모리를 재매핑하여 대응할 수 있다. 하드웨어 인터럽트 메커니즘은 특수 시스템 스택으로 전환하여 스레드 스택이 중첩된 인터럽트 사용을 고려하지 않아도 되도록 설계할 수 있는데, 1978년의 8비트 모토로라 6809는 별도의 시스템 및 사용자 스택 포인터를 제공한 것이 그 예이다.[1]

6. 3. 인터럽트 핸들러 검증

인터럽트 시스템이 정확한 상태에서 인터럽트 핸들러를 종료하는 것은 때때로 어렵고 힘든 작업일 수 있으며, 잘못 처리하면 시스템을 완전히 멈추게 하는 종류의 심각한 버그의 원인이 된다. 이러한 버그는 때때로 간헐적으로 발생하며, 잘못 처리된 예외 상황은 몇 주 또는 몇 달 동안 지속적으로 작동해야 발생할 수 있다.[1] 인터럽트 핸들러의 공식적인 검증은 매우 어렵지만, 테스트는 일반적으로 가장 빈번한 오류 모드만 식별하므로, 인터럽트 핸들러의 미묘하고 간헐적인 버그가 최종 고객에게 전달되는 경우가 많다.[1]

참조

[1] 웹사이트 The Linux Kernel Module Programming Guide, Chapter 12. Interrupt Handlers http://www.tldp.org/[...] The Linux Documentation Project 2007-05-18
[2] 웹사이트 Linux Device Drivers, Chapter 10. Interrupt Handling https://lwn.net/imag[...] O'Reilly Media 2005-01-27
[3] 문서 ユーザモードのスレッドをカーネルモードのスレッドがプリエンプトすることは一般に可能なので問題にならない。



본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.

문의하기 : help@durumis.com