[리눅스 커널 구조 원리] #10. 인터럽트 후반부 처리 (threaded IRQ)

문연수·2025년 5월 23일
0
post-thumbnail

1. 인터럽트 후반부 (bottom-half) 란?

 인터럽트는 빠르게 처리되어야 하므로 복잡한 처리가 어렵다. 그래서 인터럽트 처리를 두 단계, 전반부(top-half)와 후반부(bottom-half) 로 나누었다:

  1. 인터럽트 컨텍스트가 끝나기 전까지 처리해야 하는 급한 일들은 전반부에서 수행하고
  2. 그렇지 않은 일들을 프로세스 컨텍스트후반부로 미뤄서 처리한다.

후반부 처리 기법으로는 다음과 같은 것들이 있다:

  • IRQ 스레드(threaded IRQ)
  • Soft IRQ
  • 태스크릿(tasklet)
  • 워크큐(workqueue)

2. IRQ 스레드란

IRQ 스레드는 인터럽트를 처리하는 전용 IRQ 스레드에서 인터럽트의 후속 처리를 수행한다. IRQ 스레드는 실시간(RT: Real Time) 프로세스로이므로 일반 프로세스들에 의해 선점되지 않는다.

 필자의 시스템에는 IRQ thread 가 1개 밖에 없다. 이 thread 는 9번 인터럽트의 후반부를 전담하는 전용 스레드이다. 여기에서 priority 가 음수인데 이건 태스크의 sched classRT (Real-time) 임을 뜻한다. 따라서 일반 프로세스에 의해 선점되지 않는다. 따라서 IRQ thread 가 처리하는 작업이 많아지면 다른 프로세스들은 실행되지 않고 결국 시스템 반응 속도가 느려지게 된다.

3. IRQ 스레드 생성

 일반적으로는 request_threaded_irq() 함수를 호출할 때에 생성된다. request_threaded_irq() 함수는 __setup_irq() 를 호출하게 된다.

__setup_irq() -> setup_irq_thread() -> kthread_create() 로 호출 되어진다.

* priority 는 어디에서 설정되는가?

 책에서는 setup_irq_thread() 함수 내에서 sched_set_fifo() 를 호출해서 priority 를 설정하는 것으로 나오지만 6.15 버전 커널에서는 irq_thread() 가 직접 변경하도록 바뀌었다.

4. IRQ 스레드의 실행

 위 코드는 drivers/net/ethernet/dl2k.c 코드이다. request_irq() 함수로 등록한 인터럽트 핸들러인데 마지막에 반환하는 값이 handled 이다. 이는 인터럽트 핸들러가 인터럽트를 성공적으로 처리하였다는 뜻이다. 다른 말로 하자면 후반부가 필요 없다는 말이기도 하다. (애초에 threaded IRQ 도 아니지만)

action->handler() 가 방금 본 rio_interrupt() 와 같은 함수(인터럽트 핸들러)들을 호출하게 된다. 이 함수가 만약 IRQ_WAKE_THREAD 와 같은 값을 반환했다면, 이는 후반부에 할 일이 남아 있음을 뜻하고 따라서 후반부 핸들러가 호출한다.

 만약 rio_interrupt()IRQ_WAKE_THREAD 를 반환했다면 thread_fn 이 등록되지 않았으므로 if (unlikely(!action->thread_fn)) 에 걸려서 switch 구문을 탈출했을 것이다. 당연히 하면 안된다.

5. 전체적인 흐름도

출처: https://karatus.tistory.com/176

출처

[사이트] https://static.linaro.org/connect/yvr18/presentations/yvr18-220.pdf
[사이트] https://karatus.tistory.com/176

profile
2000.11.30

0개의 댓글