Linux Kernel(4.19) Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

230224
1178
109352


[라즈베리파이] 커널 타이머 - jiffies와 jiffies_64 변수란 7. Kernel Timer Management

jiffies에 대해 알아보기 전에 jiffies와 jiffies_64 전역 변수에 대해 짚고 가겠습니다. 리눅스 커널 코드를 보면 두 개 변수를 많이 볼 수 있는데 어떤 변수가 jiffies인지 헷갈릴 때가 많습니다.

예를 하나 들어보기 위해 다음 코드를 봅시다.
1 void pm_wakeup_ws_event(struct wakeup_source *ws, unsigned int msec, bool hard)
2 {
3 unsigned long flags;
4 unsigned long expires;
....
5 expires = jiffies + msecs_to_jiffies(msec);

pm_wakeup_ws_events() 함수 5번 줄 코드를 보면 expires이란 지역 변수에 jiffies와 msecs_to_jiffies(msec) 함수 리턴값을 저장합니다. msec 밀리 초 단위 값을 msecs_to_jiffies() 함수를 써서 HZ단위로 바꾼 후 jiffies에 더합니다. 변수 이름으로 보아 실행 마감 시각을 현재 시각 기준으로 msec 후로 설정합니다.

이번에는 다른 코드를 보겠습니다.
1 void do_timer(unsigned long ticks)
2 {
3 jiffies_64 += ticks;
4 calc_global_load(ticks);
5}

jiffies_64이란 전역 변수에 ticks이란 인자를 더합니다. 여기서 헷갈립니다. pm_wakeup_ws_events() 함수에서 쓰는 jiffies와 do_timer() 함수에서 증감하는 jiffies_64 변수는 다른 값일까요? 정답은 같은 값입니다.

실제 두 변수가 어떤 주소에 있는지 점검해 보겠습니다. 이번에는 라즈비안 리눅스 이미지를 Trace32 프로그램으로 올려서 확인합니다. 이를 위해 다음 Trace32 명령어로 두 변수가 어느 주소에 위치했는지 보겠습니다. 
var.view %d  &jiffies &jiffies_64
&jiffies = 0x80C02D00
&jiffies_64 = 0x80C02D00

확인 결과 두 변수가 같은 0x80C02D00 주소에 있습니다.

이번에는 각 변수가 어떤 값을 저장하고 있는지 살펴봅니다.
  (static long unsigned int) jiffies = 4294937296 = 0xFFFF8AD0
  (static u64) jiffies_64 = 4294937296 = 0xFFFF8AD0

같은 4294937296 값을 저장하고 있습니다.

이번에는 다른 테스트를 해보겠습니다. 다음 명령어로 강제로 jiffies 변수를 4294937297 값으로 바꿔 보겠습니다.
V %t jiffies = 4294937297

결과 두 변수가 같은 4294937297 값으로 바뀝니다.
var.view %decimal %type %hex  jiffies jiffies_64
  (static long unsigned int) jiffies = 4294937297 = 0xFFFF8AD1
  (static u64) jiffies_64 = 4294937297 = 0xFFFF8AD1

다음 링커 스크립트인 vmlinux.lds.S 파일을 봐도 jiffies와 jiffies_64는 같은 변수라는 정보를 알 수 있습니다.
[arch/arm/kernel/vmlinux.lds.S]
jiffies = jiffies_64;

위 설정으로 커널 컴파일을 하면 jiffies와 jiffies_64는 같은 주소에 위치합니다.

앞으로 리눅스 커널 코드에서 이 두 전역 변수를 보면 같은 변수라고 판단하고 코드를 분석하면 됩니다.
 
그럼 리눅스 커널에서는 왜 jiffies와 jiffies_64이란 변수가 두 개가 있을까요?
처음 리눅스 커널 코드는 타이머를 관리하는 변수인 jiffies는 u32 크기였습니다. 이후 64비트 아키텍처를 도입하면서 더 큰 크기 변수를 저장하는 jiffies_64란 전역 변수를 쓰기 시작했습니다. 그런데 문제가 생겼습니다. 기존 jiffies라는 변수로 드라이버 코드를 작성한 개발자들이 자신들이 짠 코드를 모두 jiffies_64로 수정해야 했습니다. 또한 다른 리눅스 커널 개발자들은 실행 흐름을 jiffies 변수로 처리하는데 익숙했습니다. 결과 리눅스 커널 소스 관리가 어렵게 됐습니다. 그래서 같은 주소 공간에 있는 변수로 링커 스크립트를 변경한 겁니다.

겉으로 전혀 달리 보이는 변수인데 기존 jiffies와 jiffies_64 변수가 어떻게 같이 공존할 수 있을까요? 그 이유는 두 변수는 상대적인 시각을 표현하는 값이기 때문입니다. 그래서 링커 스크립트로 jiffies와 jiffies_64를 같은 주소에 위치시켜 이런 문제를 없앤 것이죠.

다음에는 jiffies란 값을 어느 코드에서 증감하는지 알아보겠습니다.

#Reference 시스템 콜


Reference(워크큐)
워크큐(Workqueue) Overview


핑백

덧글

댓글 입력 영역