Arm Linux Kernel Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

6363
1898
209235


[리눅스커널] 시간관리: 커널 타이머 실행 시작 단계 코드 분석 8. 커널 타이머 관리

먼저 커널 타이머 1단계 세부 동작을 살펴봅니다. 다음 그림은 커널 시스템 타이머 전체 흐름도 중 1단계 부분입니다.
 
[그림 8.6] 커널 타이머 전체 흐름도에서 동적 타이머 등록 단계  

위 그림에서 [1]번 위쪽 화살표 방향으로 호출되는 함수 흐름을 살펴봅시다.

타이머 인터럽트가 발생하면 인터럽트 핸들러 함수인 arch_timer_handler_phys() 함수가 호출됩니다. 이렇게 커널 타이머는 타이머 인터럽트가 발생 후 동작을 시작합니다.  실행하고 jiffies를 +1만큼 증감하는 tich_sched_timer() 함수가 호출된 후 다음 순서로 함수 호출이 이루어집니다. 
update_process_times()
run_local_timers()

위에서 소개한 함수는 다음과 같은 처리를 합니다. 
커널 타이머가 동적 타이머를 실행할 조건을 체크
만약 동적 타이머가 등록됐으면 Soft IRQ TIMER_SOFTIRQ 서비스를 요청 

그러면 update_process_times() 함수부터 분석을 시작해볼까요?

update_process_times() 함수 분석 
먼저 update_process_times() 함수를 봅시다.
[https://github.com/raspberrypi/linux/blob/rpi-4.19.y/kernel/time/timer.c]
1  void update_process_times(int user_tick)
2 {
3 struct task_struct *p = current;
4
5 account_process_tick(p, user_tick);
6 run_local_timers();

6번 째 줄 코드와 같이 run_local_timers() 함수를 호출합니다. 참고로 이 함수는 인터럽트 컨택스트에서 실행합니다.

run_local_timers() 함수 분석 
다음 run_local_timers() 함수를 보겠습니다.
[https://github.com/raspberrypi/linux/blob/rpi-4.19.y/kernel/time/timer.c]
1 void run_local_timers(void)
2 {
3 struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]);
4
5 hrtimer_run_queues();
6
7 if (time_before(jiffies, base->clk)) {
8 if (!IS_ENABLED(CONFIG_NO_HZ_COMMON))
9 return;
10 /* CPU is awake, so check the deferrable base. */
11 base++;
13 if (time_before(jiffies, base->clk))
14 return;
15 }
16 raise_softirq(TIMER_SOFTIRQ);
17}

먼저 3번째 줄 코드를 보겠습니다.
3 struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]);

per-cpu 타입 timer_bases 전역 변수를 per-cpu 오프셋을 적용해 포인터 타입 지역 변수인 base에 저장합니다. this_cpu_ptr() 함수는 실행 중인 CPU번호에 해당하는 per-cpu 오프셋을 per-cpu 변수에 적용하는 기능입니다.

다음 7번째 줄 코드를 보겠습니다.
7 if (time_before(jiffies, base->clk)) {
8 if (!IS_ENABLED(CONFIG_NO_HZ_COMMON))
9 return;

현재 시간이 동적 타이머 만료 시각보다 이르면 함수 실행을 종료하는 동작입니다.

현재 시각 정보인 jiffies와 base->clk 를 비교합니다. 
만약 jiffies가 적으면 9번째 줄 코드 같이 "return;" 문을 실행해 run_local_timers() 함수 실행을 종료합니다. 만료할 시각 정보보다 jiffies가 더 이르면 함수 실행을 종료합니다. jiffies 는 현재 시각을 의미하고 base->clk 필드는 동적 타이머 만료 시각 정보입니다. 

이어서 16번째 줄 코드를 보겠습니다.
16 raise_softirq(TIMER_SOFTIRQ);

TIMER_SOFTIRQ 서비스 아이디로 Soft IRQ 서비스를 요청합니다.

커널 시스템 타이머를 처리하는 1단계 동작을 요약하면 다음과 같습니다.
타이머 인터럽트가 발생
동적 타이머 실행 조건 체크
TIMER_SOFTIRQ 서비스 아이디로 Soft IRQ 서비스를 요청


Soft IRQ 장에서 다음 그림과 같이 인터럽트 핸들러 처리가 끝난 후 바로 Soft IRQ 서비스를 실행한다고 배웠습니다.

리눅스 커널은 Soft IRQ 서비스 중 TIMER_SOFTIRQ 아이디로 동적 타이머를 실행합니다.
다음은 TIMER_SOFTIRQ Soft IRQ 서비스를 초기화하는 코드입니다.
[https://github.com/raspberrypi/linux/blob/rpi-4.19.y/kernel/time/timer.c]
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() 함수를 호출합니다. 세부 동작은 6.7장 Soft IRQ 절을 참고하세요.

* 강의 동영상도 있으니 같이 들으시면 좋습니다.




#커널 시간관리 목차
커널 타이머 관리 주요 개념 소개
jiffies란
커널 타이머 제어
동적 타이머 초기화
동적 타이머 등록하기
동적 타이머는 누가 언제 실행하나?
라즈베리파이 커널 타이머 실습 및 로그 분석

"혹시 궁금점이 있으면 댓글로 질문 남겨주세요. 아는 한 성실히 답글 올려드리겠습니다!"


# Reference: For more information on 'Linux Kernel';

디버깅을 통해 배우는 리눅스 커널의 구조와 원리. 1

디버깅을 통해 배우는 리눅스 커널의 구조와 원리. 2


 

핑백

덧글

댓글 입력 영역