리눅스 커널이 Bottom Half을 처리하는 대표적인 기법으로 IRQ 스레드와 Soft IRQ이 있습니다. 워크큐는 워크큐를 다루는 포스트에서 살펴볼 예정입니다. 세 가지 기법 인터럽트 후반부 처리하는 방식이 조금씩 다릅니다. 하지만 인터럽트 핸들러에서 해야 할 일을 2 단계로 나눈다는 점은 같습니다.
이 세 가지 기법의 특징이 뭔지 알아보겠습니다.
IRQ 스레드
인터럽트를 처리하는 전용 IRQ 스레드에서 인터럽트 후속 처리를 합니다. 만약 rasp란 24번 인터럽트가 있으면 “irq/24-rasp”란 IRQ 스레드가 24번 인터럽트 후반부를 전담해서 처리합니다.
Soft IRQ
인터럽트 핸들러 실행이 끝나면 바로 일을 시작합니다. 인터럽트 핸들러 바로 처리해야 할 일을 마무리한 후 인터럽트 후반부 처리를 Soft IRQ 컨택스트에서 실행합니다. Soft IRQ 서비스 핸들러 실행 도중 시간이 오래 걸리면 ksoftirqd란 프로세스를 깨우면 Soft IRQ 서비스를 종료합니다.
ksoftirqd란 프로세스에서 나머지 인터럽트 후반부를 처리하는 구조입니다.
워크큐
인터럽트 핸들러가 실행될 때 워크를 워크큐에 큐잉하고 프로세스 레벨의 워커 쓰레드에서 인터럽트 후반부 처리를 하는 방식입니다.
그러면 위에서 세 가지 기법 중 어떤 방식을 인터럽트 후반부 처리로 적용해야 할까요?
사실 인터럽트를 처리하는 드라이버를 작성할 때 어떤 기법을 쓸 지는 드라이버 담당자의 몫입니다. 인터럽트 발생 빈도와 이를 처리하는 시나리오에 따라 위 세 가지 기법을 적절히 조합해서 드라이버 코드를 작성해야 합니다. 이를 위해서 인터럽트를 시스템에서 처리하는 방식과 인터럽트가 얼마나 자주 발생하는지를 알아야 합니다.
리눅스 디바이스 드라이버를 개발할 때 다양한 하드웨어 디바이스를 인터럽트로 제어합니다. 또한 인터럽트를 관리하는 방식도 리눅스 시스템 마다 다릅니다.
어떤 인터럽트 방식을 적용해야 할까?
이런 다양한 상황에서 어떤 인터럽트 방식을 적용해야 할지를 Q/A로 정리하면 다음과 같습니다.
Q: 인터럽트가 1초에 수 백번 발생하는 디바이스의 경우 어떤 인터럽트 후반부 기법을 적용해야 할까?
A: IRQ 스레드 방식과 워크큐 방식은 그리 적합하지 않습니다. IRQ 스레드는 RT 프로세스로 구동됩니다. 인터럽트가 많이 발생하면 IRQ 스레드를 깨워야 하고 IRQ 스레드는 RT 프로세스로 구동하므로 다른 프로세스들이 선점 스케줄링을 할 수 없습니다. IRT 스레드 핸들러 실행 시간이 조금이라도 길어지면 다른 프로세스들이 실행을 못하고 대기해야 하므로 시스템 반응 속도가 느려질 수 있습니다.
만약 IRQ 스레드 방식을 적용해야 한다면 IRQ 스레드 핸들러 함수 실행 시간이 매우 짧아야 합니다. 예를 들면, IRQ 스레드 핸들러 함수에 printk() 함수와 같이 커널 로그를 출력하는 코드도 되도록 입력하지 말아야 합니다.
또한 워크큐를 실행하는 워커 스레드는 일반 프로세스로 프로세스 우선 순위가 높지 않습니다.
인터럽트 발생 횟수만큼 워크 핸들러가 실행을 못할 수 있습니다.
따라서 인터럽트가 자주 발생하는 디바이스는 Soft IRQ나 태스크릿 방식을 적용하는 것이 바람직합니다.
Q. 현재 개발 중인 시스템은 인터럽트 개수가 200개 정도된다. 어떤 방식을 적용하면 좋을까?
1초에 인터럽트가 수 백번 발생하는 경우를 제외하곤 IRQ 스레드 방식을 적용하면 별 문제가 없습니다. 그런데 인터럽트 개수만큼 IRQ 스레드를 생성하면 기본으로 프로세스를 관리할 때 필요한 태스크 디스크립터와 같은 메모리 공간을 써야 합니다. 만약 현재 개발 중인 시스템 RAM 용량이 8G 이상이면 별 문제가 되지 않을 것입니다.
인터럽트가 발생 빈도가 낮고 빠른 시간에 인터럽트 후반부를 처리하지 않아도 될 경우 워크큐 기법을 적용하는 것도 좋습니다.
어떤 인터럽트 후반부 방식을 적용할지 결정하는 것은 어려운 일입니다. 정답이 없기 때문입니다. 이런 상황에서 필요한 것이 최적화인 것 같습니다. 인터럽트 후반부 단계에서 인터럽트 처리를 최적화하도록 설계를 잘 하려면 먼저 커널이 인터럽트를 처리하는 세부 동작과 인터럽트 후반부 기법들의 세부 구현 방식을 잘 알고 있어야 합니다.
'리눅스 커널의 구조와 원리 > 6. 인터럽트 후반부 처리' 카테고리의 다른 글
[리눅스커널] IRQ 스레드를 생성하는 시점 확인하기 (0) | 2024.06.05 |
---|---|
[리눅스커널] 인터럽트 후반부 - Top Half/Bottom Half 란 무엇일까? (0) | 2024.05.27 |
[리눅스커널] IRQ 스레드 생성 과정을 디버깅으로 알아보기 (0) | 2019.03.10 |
[리눅스커널] IRQ 스레드를 생성하는 샘플 코드 살펴보기 (0) | 2019.03.10 |
[리눅스커널] IRQ 스레드(threaded IRQ)에 대한 소개 (0) | 2019.03.10 |