Arm Linux Kernel Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

75261
1501
219117


[리눅스커널] 시간관리: time_after()/time_before() 함수 사용 예시 알아보기 8. 커널 타이머 관리

이번에는 time_after()/time_before() 함수를 써서 실행 시간 흐름을 제어하는 예제 코드를 살펴보겠습니다. .

다음 소개할 코드는 워크큐 와치독 타이머인 wq_watchdog_timer_fn() 함수입니다.
[https://github.com/raspberrypi/linux/blob/rpi-4.19.y/kernel/workqueue.c]
01 static unsigned long wq_watchdog_thresh = 30;
02 static void wq_watchdog_timer_fn(struct timer_list *unused)
03 {
04 unsigned long thresh = READ_ONCE(wq_watchdog_thresh) * HZ;
...
05 /* did we stall? */
06 if (time_after(jiffies, ts + thresh)) {
07 lockup_detected = true;
08 pr_emerg("BUG: workqueue lockup - pool");
09 pr_cont_pool_info(pool);
10 pr_cont(" stuck for %us!\n",
11 jiffies_to_msecs(jiffies - pool_ts) / 1000);
12 }

이 함수는 워크큐에 큐잉한 워크가 정해진 시간 내에 실행했는지 점검합니다.

6번째 줄을 보면 jiffies와 (ts+thread)를 비교해서 jiffies가 더 크면 time_after() 함수는 1을 반환합니다. 워크큐 락업이라고 판단하고 if 문 내에서 에러 메시지를 출력하는 코드를 실행합니다. 현재 시각이 지정한 마감 시각보다 큰지 점검하는 동작입니다.

(ts + thresh) 은 가장 최근에 워크가 실행했던 시각 정보입니다. wq_watchdog_thresh 가 30이니 워크를 워크큐에 큐잉하고 30초 동안 처리하지 못하면 워크큐 스톨(Stall)이라고 판단합니다.

이번에는 Soft IRQ 핵심인 __do_softirq() 함수 코드를 확인해 봅시다.
[https://github.com/raspberrypi/linux/blob/rpi-4.19.y/kernel/softirq.c]
01 asmlinkage __visible void __softirq_entry __do_softirq(void)
02 {
03 unsigned long end = jiffies + MAX_SOFTIRQ_TIME;
...
04 restart:
...
05 while ((softirq_bit = ffs(pending))) {
06 unsigned int vec_nr;
07 int prev_count;
...
08 trace_softirq_entry(vec_nr);
09 h->action(h);
10 trace_softirq_exit(vec_nr);
...
11 }
12
13 rcu_bh_qs();
14 local_irq_disable();
15
16 pending = local_softirq_pending();
17 if (pending) {
18 if (time_before(jiffies, end) && !need_resched() &&
19     --max_restart)
20 goto restart;
21
22 wakeup_softirqd();
23 }

__do_softirq() 함수는 Soft IRQ 서비스 핸들러 실행 시간이 2ms를 넘었는지 점검합니다. 
3번째 줄 코드를 보겠습니다. 
03 unsigned long end = jiffies + MAX_SOFTIRQ_TIME;

현재 시간 정보인 jiffies에 msecs_to_jiffies(2) 함수 결괏값을 더해 end라는 지역 변수에 저장합니다. 

04~14번째 줄 구간 코드는 Soft IRQ 서비스 핸들러를 실행하는 동작입니다.

이번엔 18번째 줄 코드를 보겠습니다. 
우리는 time_before() 함수를 써서 실행 시간 흐름을 배우는 것이 목적이니 다른 조건은 무시하겠습니다.

timer_before() 함수 실행 조건을 점검해볼까요? 
현재 시각인 jiffies가 end보다 작으면 if 문을 실행해서 restart 레이블을 실행해 Soft IRQ 서비스를 실행합니다. 아니면 22번째 줄 코드와 같이 wakeup_softirqd() 함수를 호출해서 ksoftirqd 스레드를 깨웁니다.

여기서 현재 시각인 jiffies가 end보다 작은지 점검하는 것은 어떤 의미일까요? 
처음 __do_softirq() 함수를 실행했을 때 기준으로 2ms 후를 마감시각을 end에 저장했습니다. Soft IRQ 서비스를 실행한 다음 jiffies가 end보다 작으면 Soft IRQ 서비스를 2ms내에 실행했다고 볼 수 있습니다. 


리눅스 커널 코드를 보면 time_after()와 time_before() 함수를 써서 코드 실행 시간을 제어하는 루틴을 자주 볼 수 있습니다. 이 두 함수 원리를 제대로 익히면 관련 코드를 바로 이해할 수 있습니다.

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





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

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


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

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

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



 







핑백

덧글

댓글 입력 영역