인터럽트는 빠르게 처리되어야 하므로 복잡한 처리가 어렵다. 그래서 인터럽트 처리를 두 단계, 전반부(top-half)와 후반부(bottom-half) 로 나누었다:
전반부
에서 수행하고후반부
로 미뤄서 처리한다.후반부 처리 기법으로는 다음과 같은 것들이 있다:
IRQ 스레드
는 인터럽트를 처리하는 전용 IRQ 스레드에서 인터럽트의 후속 처리를 수행한다. IRQ 스레드는 실시간(RT: Real Time) 프로세스로이므로 일반 프로세스들에 의해 선점되지 않는다.
필자의 시스템에는 IRQ thread
가 1개 밖에 없다. 이 thread
는 9번 인터럽트의 후반부를 전담하는 전용 스레드이다. 여기에서 priority
가 음수인데 이건 태스크의 sched class
가 RT (Real-time)
임을 뜻한다. 따라서 일반 프로세스에 의해 선점되지 않는다. 따라서 IRQ thread
가 처리하는 작업이 많아지면 다른 프로세스들은 실행되지 않고 결국 시스템 반응 속도가 느려지게 된다.
일반적으로는 request_threaded_irq()
함수를 호출할 때에 생성된다. request_threaded_irq()
함수는 __setup_irq()
를 호출하게 된다.
__setup_irq()
-> setup_irq_thread()
-> kthread_create()
로 호출 되어진다.
책에서는 setup_irq_thread()
함수 내에서 sched_set_fifo()
를 호출해서 priority 를 설정하는 것으로 나오지만 6.15 버전 커널에서는 irq_thread()
가 직접 변경하도록 바뀌었다.
위 코드는 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
구문을 탈출했을 것이다. 당연히 하면 안된다.
출처: https://karatus.tistory.com/176
[사이트] https://static.linaro.org/connect/yvr18/presentations/yvr18-220.pdf
[사이트] https://karatus.tistory.com/176