Linux Kernel(4.14) Hacks

rousalome.egloos.com

포토로그 Kernel Crash




[라즈베리파이] 커널 타이머 -동적 타이머는 누가 언제 호출하나? (1) [라즈베리파이] 타이머관리

이전에 동적 타이머를 설정하는 코드 흐름까지 알아봤습니다. 이 과정을 요약하면 다음과 같습니다.  
1. 동적 타이머를 표현하는 자료 구조인 struct timer_list 구조체에 기본 정보를 채운 다음 add_time() 혹은 mod_time() 함수를 호출합니다. 동적 타이머 기본 정보는 타이머 만료 시각(HZ단위)과 동적 타이머 핸들러 함수와 매개 변수입니다.

2. 동적 타이머를 초기화했을 때 실행했던 CPU 번호 기준으로 per-cpu 오프셋을 적용해서 timer_base 주소를 읽습니다. 이 주소에는 struct timer_base 구조체 멤버가 있는데 타이머 벡터 해시 인덱스에 동적 타이머를 등록했습니다.

이어서 이번에는 동적 타이머를 누가 언제 처리하는지 살펴봅니다. 동적 타이머는 커널 시스템 타이머가 호출하며 커널 타이머는 Soft IRQ 서비스 중 하나로 처리합니다. 이전 절에서는 동적 타이머를 실행하는 코드만 분석했는데 이번에는 시스템 관점으로 만료되는 동적 타이머를 어떻게 처리하는지 점검합니다. 이번에는 조금 더 큰 그림을 그리면서 코드를 볼 필요가 있습니다.

리눅스 커널은 Soft IRQ 서비스 중 TIMER_SOFTIRQ이란 아이디로 타이머 처리를 합니다.
이제 코드를 보겠습니다.
void __init init_timers(void)
{
init_timer_cpus();
open_softirq(TIMER_SOFTIRQ, run_timer_softirq);
}

위 코드는 TIMER_SOFTIRQ이란 아이디로 Soft IRQ 서비스 핸들러는 run_timer_softirq() 함수로 등록합니다. 이후 TIMER_SOFTIRQ이란 서비스 아이디로 Soft IRQ 서비스 요청을 하면 해당 핸들러인 run_timer_softirq() 함수를 호출합니다.

이 과정은 다음 그림으로 설명할 수 있습니다.


이제 커널 시스템 타이머가 어떤 순서로 동적 타이머를 처리하는지 단계별로 확인하겠습니다.

먼저 1단계입니다. 
타이머 인터럽트가 발생하면 화살표 흐름으로 인터럽트 벡터부터 run_local_timer() 함수까지 실행합니다. 이 run_local_timer() 함수에서 TIMER_SOFTIRQ이란 아이디로 Soft IRQ 서비스 요청을 합니다. 콜스택을 유심히 보면 __irq_svc 심볼이 보이니 이 함수는 인터럽트 컨택스트에서 실행됩니다.

다음 2단계를 알아봅시다. 인터럽트 처리가 끝나면 irq_exit() 함수를 호출해서 Soft IRQ 서비스 루틴을 실행합니다. 인터럽트 컨택스트가 끝나고 Soft IRQ 컨택스트가 시작하는 시점입니다.

이제 3단계입니다. irq_exit() 함수에서 Soft IRQ 서비스 요청 여부를 확인합니다. 1 단계에서 이미 TIMER_SOFTIRQ 아이디로 Soft IRQ 서비스 요청을 했으니 invoke_softirq() 함수를 호출합니다. 이후 __do_softirq() 함수에서 TIMER_SOFTIRQ 아이디 Soft IRQ 서비스 핸들러인 run_timer_softirq() 함수를 실행합니다.

마지막 4단계를 알아봅시다. __run_timers() 함수를 호출해서 per-cpu 타입 변수인 timers_base 전역 변수에 접근해 만료될 동적 타이머들을 로딩합니다. 이때 타이머 해시 테이블에 등록된 struct timer_list 주소에 접근해서 동적 타이머들을 해제하고 타이머 핸들러 함수를 호출합니다.

커널 타이머는 Soft IRQ 서비스 중 하나로 처리하므로 Soft IRQ 처리 흐름에 대해 잘 알아야 합니다.
다음 시간에 이제 위 그림에서 설명해 드린 단계별로 코드를 살펴보겠습니다.



핑백

덧글

댓글 입력 영역