임베디드 트랙 스터디 5주차 - 인터럽트 후반부 기법 3종 비교 과제 준비
리눅스 커널 인터럽트 처리의 top half/bottom half 구조를 실제로 구현해보는 최종 과제를 시작했습니다. 타이머 인터럽트로 접근하기로 했는데, 하드웨어 IRQ 라인이 없는 상황에서 어떻게 인터럽트를 만들지부터 막혔습니다.
학습 주제
- 주제: 리눅스 커널 인터럽트 전반부/후반부(top half/bottom half) 처리, 그리고 Threaded IRQ / Workqueue / Tasklet 세 가지 후반부 기법 비교
- 날짜: 2026년 8월 12일
- 배경: 경희대 ENIAC 동아리 "임베디드 개발을 위한 리눅스 커널 탐방" 스터디 5주차 최종 과제 준비
과제 요구사항 정리
먼저 자료를 읽고 뭘 해야 하는지부터 명확히 했습니다. 핵심은 이렇습니다.
- 인터럽트 전반부/후반부 로직을 모두 구현한 드라이버 하나를 만들고
- 그 드라이버에 Threaded IRQ, Workqueue, Tasklet 세 가지 후반부 기법을 각각 적용해서
- ftrace로 TH entry/exit, BH entry/exit, BH time, total 같은 항목들을 측정해서 비교하는 보고서를 쓰는 것
인터럽트 소스는 버튼, 센서, 타이머, 소프트웨어 인터럽트 중 아무거나 선택 가능했고, 저는 별도 하드웨어 없이 순수 코드로 구현할 수 있다는 점 때문에 타이머 인터럽트를 골랐습니다. 보고서는 최대 3장 이내로, 드라이버 기능 설명 → 세 기법의 ftrace 로그 → 소요 시간 표와 비교 순서로 쓰면 됩니다.
탐구 과정: sysfs와 디바이스 트리 복습
과제 코드를 짜기 전에 자료 앞부분에 나온 배경 지식을 먼저 정리했습니다.
sysfs는 /sys/ 하위 경로를 파일처럼 읽고 쓰는 것만으로 디바이스를 제어할 수 있게 해주는 커널 인터페이스입니다. /sys/class/power_supply/BAT0/capacity처럼 익숙한 경로들이 사실 이 구조 위에서 동작한다는 걸 다시 확인했습니다.
**디바이스 트리(DT)**는 하드웨어 명세를 트리 구조로 추상화한 것으로, compatible 문자열로 드라이버와 매칭됩니다. 오버레이는 이런 형태로 작성합니다.
fragment@0 {
target-path = "/";
__overlay__ {
...
};
};
이걸 dtc -@ -I dts -O dtb -o out.dtbo in.dts로 컴파일한 다음 /boot/firmware/overlays/에 넣으면 부팅 시 루트 노드에 자동으로 추가됩니다. 드라이버 쪽에서는 of_device_id 배열에 동일한 .compatible 문자열을 넣고 MODULE_DEVICE_TABLE(of, ...)로 등록하면 연결되는데, platform_driver의 .probe/.remove가 이 연결의 핵심 훅이라는 걸 짚어둘 필요가 있었습니다.
강의 예제로는 holy_cow_button이라는 GPIO 버튼 드라이버가 쓰였고, 강사 화면에서 이미 tasklet, threaded_irq, workque 세 디렉토리 구조가 보였던 것으로 봐서 이번 최종 과제와 똑같은 3종 비교 구조가 강의에서 예시로 다뤄졌던 것 같습니다.
막혔던 지점: 하드웨어 IRQ 없이 타이머 인터럽트 만들기
타이머 인터럽트를 쓰기로 했는데, 문제는 실제 하드웨어 IRQ 라인이 없다는 점이었습니다. 버튼이나 센서라면 물리적인 핀에서 인터럽트가 발생하지만, 타이머는 그 자체로는 IRQ 컨텍스트를 만들어주지 않습니다. 이 부분을 어떻게 풀지 두 가지 방향을 놓고 고민했습니다.
1) hrtimer 콜백을 top half로 사용
hrtimer 콜백은 hardirq 컨텍스트에서 실행되기 때문에 실질적으로 ISR과 동일한 성격을 가집니다. 별도 배선 없이 순수 커널 코드만으로 완결되고, Threaded IRQ는 request_threaded_irq 대신 동일한 동작을 하는 kthread로 대체 구현하면 됩니다.
2) GPIO 루프백으로 진짜 하드웨어 IRQ 생성
출력 GPIO를 타이머로 토글하고 점퍼선으로 입력 GPIO에 연결해서 실제 edge-triggered 인터럽트를 발생시키는 방법. request_threaded_irq를 그대로 쓸 수 있어서 정석에 가깝지만, 물리적으로 점퍼선을 연결해야 합니다.
결국 별도 하드웨어 배선 없이 진행할 수 있다는 점 때문에 hrtimer 방식으로 결정했습니다. hardirq 컨텍스트에서 콜백이 돈다는 특성을 이용하면 실제 IRQ 핸들러와 거의 같은 조건에서 비교 실험을 할 수 있다는 게 이해가 되는 지점이었습니다.
원격 보드 환경 점검
측정은 원격 라즈베리파이(ssh -p 2224)에서 진행하기로 했는데, 접속해서 환경을 살펴보니 예상치 못한 문제가 있었습니다.
- 보드는 Raspberry Pi 4 Model B Rev 1.5, Debian 13(trixie)
- 현재 부팅 중인 커널이
6.12.95-v8+인데, 이게 apt 표준 커널이 아니라 커스텀 컴파일 커널로 보임 (이전 주차 커널 재빌드 실습의 결과물로 추정) - 결정적으로
/lib/modules/6.12.95-v8+/build가 존재하지 않음 — 즉 지금 부팅 중인 커널에 대응하는 빌드 트리가 없어서 이 상태로는 커널 모듈(.ko)을 컴파일할 수 없음 - apt로 설치된 헤더는
linux-headers-6.18.34+rpt-rpi-v8,linux-headers-6.18.34+rpt-rpi-2712뿐이라 현재 커널 버전과 맞지 않음
/boot/firmware/를 뒤져보니 부팅 이미지가 여러 개 있었습니다.
kernel8.img— 현재 사용 중인 커스텀 커널kernel8-stock-backup.img— apt 표준 커널로 추정되고, 6.18.34 헤더와 매칭될 가능성이 높아서 바로 모듈 빌드가 가능할 것으로 보임kernel8-custom-broken.img— 이름으로 봐서 실패했던 커스텀 빌드kernel_2712.img— Pi 5용
dtc, gcc, make는 다 설치되어 있어서 DT 오버레이 컴파일 자체는 문제없었지만, ftrace 디렉토리(/sys/kernel/debug/tracing)는 root 권한이 필요해서 지금 세션에서는 접근이 막혀 있었습니다. 예전 주차에 썼던 것으로 보이는 start_ftrace.sh, finish_ftrace.sh 스크립트도 발견했는데, 이건 스케줄링 추적용이라 이번 목적과는 다른 것 같습니다. 이전 드라이버 실습 소스나 6.12.95 커널의 원본 빌드 트리는 파일시스템 전체를 뒤져봐도 찾지 못했습니다.
이해한 내용
이번에 정리하면서 확실해진 것들:
- top half(hardirq)와 bottom half의 경계는 "빠르게 처리해야 하는가 vs 나중에 처리해도 되는가"의 문제이고, hrtimer 콜백이 hardirq 컨텍스트에서 도는 이유도 결국 타이밍 정확도 때문이라는 걸 다시 확인했습니다.
- 모듈 빌드에는 부팅 중인 커널과 정확히 매칭되는 빌드 트리가 필요하다는 당연한 사실을 실제로 막혀보고서야 체감했습니다. 헤더 패키지가 설치되어 있어도 커널 버전이 다르면 소용없다는 점.
- DT 오버레이와 드라이버의
compatible매칭 구조는 이전에 배운 걸 다시 짚어보니 확실히 익숙해졌습니다.
실전 적용
- hrtimer 기반 top half 드라이버를 먼저 하나 만들고, 여기에 Threaded IRQ(대체 kthread), Workqueue, Tasklet 세 버전을 각각 붙여서 비교 실험할 계획입니다.
- 원격 보드 환경 문제부터 해결해야 실습이 가능한 상태라, 다음 단계로 넘어가기 전에 커널 환경을 정리하는 게 우선입니다.
추가 학습 계획: 미해결 상태로 남은 것들
이번 세션은 아래 두 가지를 결정하지 못하고 끊겼습니다. 다음에 이어서 풀어야 합니다.
- 커널 환경을 어떻게 맞출지
kernel8-stock-backup.img를kernel8.img로 되돌려서 재부팅하면 이미 헤더가 설치된 6.18.34 커널로 바로 모듈 빌드가 가능해 보이지만, 왜 커스텀 커널로 바꿨었는지(이번 과제에 필요한 특정 설정이 있었는지) 불명확해서 리스크가 있습니다.- 다른 대안은 6.12.95-v8+를 빌드했던 원본 소스 트리를 찾아서(다른 PC나 빌드 서버에 있을 가능성) Pi로 가져와
modules_prepare를 진행하는 것.
- sudo 권한 처리 방식: ftrace 설정, 커널 이미지 교체, insmod 등에 root 권한이 필요한데, 이 부분을 어떻게 처리할지 결정해야 합니다.
다음 학습에서는 이 두 가지부터 결론을 내고, hrtimer 기반 드라이버 코드 작성으로 넘어갈 예정입니다.