Arm Linux Kernel Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

6363
1898
209235


[리눅스커널][태스크릿] 태스크릿은 언제 실행할까? tasklet_action_common() 분석 6. 인터럽트 후반부 처리

태스크릿은 언제 실행할까?

태스크릿은 Soft IRQ 서비스 중 하나입니다. 따라서 Soft IRQ 서비스를 실행하는 __do_softirq() 함수에서 태스크릿 서비스 핸들러 함수를 호출합니다.

Soft IRQ 전체 흐름도에서 태스크릿 서비스를 실행하는 그림을 보겠습니다.
 
[태스크릿 전체 흐름도에서 태스크릿 실행 단계]

[1] 단계에서 인터럽트가 발생한 후 인터럽트 핸들러에서 태스크릿 스케줄링을 실행했습니다. 이번엔 [2] 단계에서 태스크릿 서비스 핸들러가 호출하는 과정을 살펴봅니다.

전체 Soft IRQ 구조에서 __do_softirq() 함수가 호출되는 흐름은 6.8 절을 참고하세요. 

태스크릿 서비스 핸들러인 tasklet_action() 함수를 실행하는 출발점은 __do_softirq() 함수입니다.
[https://elixir.bootlin.com/linux/v4.19.30/source/kernel/softirq.c]
01 asmlinkage __visible void __softirq_entry __do_softirq(void)
02 {
...
03 while ((softirq_bit = ffs(pending))) {
04 unsigned int vec_nr;
05 int prev_count;
06
07 h += softirq_bit - 1;
08
09 vec_nr = h - softirq_vec;
10 prev_count = preempt_count();
11
12 kstat_incr_softirqs_this_cpu(vec_nr);
13
14 trace_softirq_entry(vec_nr);
15 h->action(h);
16 trace_softirq_exit(vec_nr);
...
17

위 함수 15 번째 줄 코드에서 tasklet_action() 함수를 호출합니다.

__do_softirq() 함수에서 호출하는 tasklet_action() 함수를 보겠습니다.
[https://elixir.bootlin.com/linux/v4.19.30/source/kernel/softirq.c]
1 static __latent_entropy void tasklet_action(struct softirq_action *a)
2 {
3 tasklet_action_common(a, this_cpu_ptr(&tasklet_vec), TASKLET_SOFTIRQ);
4 }

tasklet_action() 함수가 특별히 하는 일은 없습니다. 다음 인자로 tasklet_action_common() 함수를 호출합니다.
 - a: struct softirq_action 타입 
 - this_cpu_ptr(&tasklet_vec): tasklet_vec 전역 변수에서 percpu 오프셋을 적용 주소
 - TASKLET_SOFTIRQ: 태그크릿 플래그

this_cpu_ptr() 함수는 현재 실행 중인 CPU 번호에 맞게 percpu 오프셋을 적용한 주소로 변환합니다.
 
다음 tasklet_action_common() 함수를 보겠습니다.
[https://elixir.bootlin.com/linux/v4.19.30/source/kernel/softirq.c]
01 static void tasklet_action_common(struct softirq_action *a,
02    struct tasklet_head *tl_head,
03    unsigned int softirq_nr)
04 {
05  struct tasklet_struct *list;
06 
07  local_irq_disable();
08  list = tl_head->head;
09 tl_head->head = NULL;
10 tl_head->tail = &tl_head->head;
11 local_irq_enable();
12
13 while (list) {
14 struct tasklet_struct *t = list;
15
16 list = list->next;
17
18 if (tasklet_trylock(t)) {
19 if (!atomic_read(&t->count)) {
20 if (!test_and_clear_bit(TASKLET_STATE_SCHED,
21 &t->state))
22 BUG();
23 t->func(t->data);
24 tasklet_unlock(t);
25 continue;
26 }
27 tasklet_unlock(t);
28 }
...
29 }
30 } 

먼저 태스크릿 실행 조건을 확인하는 구문부터 보겠습니다.
19 if (!atomic_read(&t->count)) {
20 if (!test_and_clear_bit(TASKLET_STATE_SCHED,
21 &t->state))
22 BUG();

19 번째 줄에서는 struct tasklet_struct 타입 &t->count가 0인지를 체크합니다.
만약 0이 아니면 20~25 번째 줄 코드를 실행하지 않습니다.

다음은 struct tasklet_struct 타입 &t->state가 TASKLET_STATE_SCHED 플래그가 아니면 22 번째 줄 코드인 BUG() 함수를 실행해 커널 패닉을 유발합니다.

리눅스 커널에서 BUG() 함수는 시스템을 정상적으로 구동할 수 없는 치명적인 오류가 있을 때 호출합니다.

23 번째 줄은 태스크릿 핸들러 함수를 호출합니다.
23 t->func(t->data);
 
태스크릿 핸들러 함수가 실행하는 흐름입니다.

예를 들면 keyboard_tasklet 태스크릿은 다음과 같이 func 필드에는 kbd_bh() 함수 주소가 있습니다.
  (static struct tasklet_struct) keyboard_tasklet = (
    (struct tasklet_struct *) next = 0x0 = ,
    (long unsigned int) state = 0x0,
    (atomic_t) count = ((int) counter = 0x0),
    (void (*)()) func = 0x8051F144 = kbd_bh,
    (long unsigned int) data = 0x0)


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





"이 포스팅이 유익하다고 생각되시면 댓글로 응원해주시면 감사하겠습니다.  
혹시 글을 읽고 궁금점이 있으면 댓글로 질문 남겨주세요. 상세한 답글 올려 드리겠습니다!"

# Reference 인터럽트 후반부 처리








6.9 Soft IRQ 서비스는 누가 언제 처리하나?




6.13 Soft IRQ 디버깅
6.13.1 ftrace Soft IRQ 이벤트 분석 방법
6.13.2 /proc/softirqs로 Soft IRQ 서비스 실행 횟수 확인


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

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

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


 



핑백

덧글

댓글 입력 영역