본문 바로가기

리눅스 커널의 구조와 원리/6. 인터럽트 후반부 처리

[리눅스커널] 인터럽트 후반부 - Top Half/Bottom Half 란 무엇일까?

이전 포스트에서 인터럽트 컨택스트에서 인터럽트 핸들링을 빠른 시간에 마무리해야 한다고 설명을 드렸습니다. 또한 시간이 오래 걸리는 함수를 호출하면 시스템은 커널 패닉과 같이 시스템이 오동작 할 수 있다고 소개했습니다.

여기서 한 가지 의문이 생깁니다.

인터럽트가 발생하면 인터럽트 핸들러에서 처리할 일이 많을 때는 어떻게 해야 할까? 

 

 

이럴 때 해야 할 일을 2가지로 나누면 됩니다. 빨리 처리해야 하는 일과 조금 있다가 처리해도 되는 일입니다. 임베디드 용어로,

  • 인터럽트가 발생 후 빨리 처리해야 하는 일은 Top Half
  • 조금 있다가 처리해도 되는 일은 Bottom Half

라고 말합니다. 

인터럽트 핸들러가 하는 일은 Top Half라고 할 수 있습니다. Bottom Half는 인터럽트에 대한 처리를 프로세스 레벨에서 수행하는 방식입니다. 

리눅스 커널에서 Bottom Half을 어떤 방식으로 구현할까요? 
인터럽트 핸들러는 일하고 있던 프로세스를 멈춘 시점인 인터럽트 컨택스트에서 실행합니다. 급하게 처리해야 할 일은 인터럽트 컨택스트에서 처리하고 조금 후 실행해도 되는 일은 프로세스 레벨에서 처리합니다. 이를 위해 커널에서 대표적으로 다음과 같은 기법을 인터럽트 후반부 기법으로 지원합니다.


   - threaded IRQ(IRQ 스레드)
   - Soft IRQ
   - 워크큐

인터럽트 컨택스트와 커널 쓰레드 레벨에서 어떤 코드를 동작할 때 어떤 차이점이 있을까요?
우선 인터럽트 컨택스트에서는 호출할 수 있는 함수가 제한돼 있습니다. 

리눅스 커널에서는 인터럽트 컨택스트에서 많은 일을 하는 함수를 호출할 때 경고 메시지를 출력하거나 커널 패닉을 유발해서 시스템 실행을 중단시킵니다. 예를 들어 스케줄링을 지원하는 뮤텍스나 schedule() 함수를 쓰면 커널은 강제로 커널 패닉을 유발합니다.

뮤텍스 함수는 스케줄링 동작과 연관돼 있습니다. 프로세스가 뮤텍스를 획득하려고 시도하는데 만약 다른 프로세스가 이미 뮤텍스를 획득했으면 휴면에 진입합니다.

그런데 인터럽트 컨택스트에 비해 커널 쓰레드에서는 커널이 제공하는 스케쥴링을 포함한 모든 함수를 쓸 수 있습니다. 그래서 시나리오에 따라 유연하게 코드를 설계할 수 있습니다.

예를 들어 인터럽트가 발생했을 때 이를 유저 공간에 알리고 싶을 경우가 있습니다. 안드로이드 디바이스 같은 경우에 터치를 입력하면 발생하는 인터럽트를 uevent로 유저 공간에 알릴 수 있습니다. 유저 공간에 uevent를 보내는 동작은 시간이 오래 걸리는 일입니다. 따라서 시간이 오래 걸리는 코드는 인터럽트 후반부에서 처리하도록 드라이버 구조를 잡아야 합니다.