ARM Linux Kernel Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

198239
1625
172595


[리눅스커널] 프로세스: 태스크 디스크립터(task_struct 구조체) - 프로세스 연결 리스트 4. 프로세스(Process) 관리

task_struct 구조체의 tasks 필드는 list_head 구조체로서 연결 리스트 타입입니다. 커널에서 구동 중인 모든 프로세스는 tasks 연결 리스트에 등록돼 있습니다. 그렇다면 프로세스의 태스크 디스크립터 tasks 연결 리스트 필드는 언제 init 프로세스의 태스크 디스크립터 tasks 연결 리스트에 등록될까요?

프로세스는 처음 생성될 때 init_task 전역변수 필드인 tasks 연결 리스트에 등록됩니다. 프로세스를 생성할 때 호출되는 copy_process() 함수를 보면서 처리 과정을 살펴보겠습니다.
 
https://elixir.bootlin.com/linux/v4.19.30/source/kernel/fork.c
1 static __latent_entropy struct task_struct *copy_process(
2 unsigned long clone_flags,
3 unsigned long stack_start,
4 unsigned long stack_size,
5 int __user *child_tidptr,
6 struct pid *pid,
7 int trace,
8 unsigned long tls,
9 int node)
10 {
11 struct task_struct *p;
12 p = dup_task_struct(current, node);
...
13 list_add_tail_rcu(&p->tasks, &init_task.tasks);

12번째 줄을 실행하면 커널로부터 태스크 디스크립터를 할당받습니다. 다음 13번째 줄에서는 init_task.tasks 연결 리스트의 마지막 노드에 현재 프로세스의 task_struct 구조체의 tasks 주소를 등록한다.

자료구조를 변경하는 커널 코드를 읽으니 감이 잘 오지 않습니다. 이번에는 프로세스 태스크 디스크립터의 전체 구조에서 tasks 필드를 확인해 봅시다.

1  (static struct task_struct) [D:0xA1A171B8] init_task = (
2    (long int) [D:0xA1A171B8] state = 0,
3    (void *) [D:0xA1A171BC] stack = 0xA1A00000,
...
4    (struct sched_info) [D:0xA1A174A8] sched_info = ((long unsigned int) pcount = 0,
5    (struct list_head) [D: 0xA1A174C8] tasks = (
6      (struct list_head *) [D:0xA1A174E8] next = 0xA1618310 -> (
7        (struct list_head *) [D:0xA1618330] next = 0xB1618A70,
8        (struct list_head *) [D:0xA1618334] prev = 0xA1A174E8),
9      (struct list_head *) [D: 0xA1A174CC] prev = 0xA7778330),

init_task.tasks 필드 구조체는 list_head 구조체의 연결 리스트이며 6~7번째 줄의 디버깅 정보와 같이 next 필드를 가리키고 있습니다. init_task 전역변수는 task_struct 구조체와 같이 태스크 디스크립터라는 점을 기억합시다.

6번째 줄에서 init_task.tasks.next는 0xA1618330 주소를 가리키고 있습니다. 이 주소는 어떤 의미일까요? 바로 init_task.tasks 연결 리스트에 추가된 다음 프로세스의 task_struct 구조체의 tasks 필드 주소를 가리킵니다. 이 처리 흐름을 그림으로 표현하면 다음과 같습니다.


그림 4.14에서 [1]로 표시된 부분을 보면 태스크 디스크립터의 next 필드는 0xA1618310 주소를 가리킵니다. 여기서 중요한 질문을 던지겠습니다. 0xA1618310 주소의 정체는 무엇일까요? 바로 연결 리스트에 등록된 다음 프로세스 태스크 디스크립터의 next 필드 주소를 의미합니다. [1]에서 시작된 화살표 끝부분이 가리키는 박스를 보면 0xA1618310 주소가 보입니다. 이는 0xA1618000 주소에 있는 태스크 디스크립터의 tasks 필드의 주소인 것입니다.

이번에는 그림 4.14에서 [2]로 표시된 부분을 눈으로 따라가 보겠습니다. next 필드는 0xA16191B0 주소를 가리킵니다. 0xA16191B0 주소는 연결 리스트에 등록된 다음 프로세스 태스크 디스크립터의 next 필드 주소를 의미합니다. 모든 프로세스가 이렇게 연결 리스트로 등록돼 있습니다. 이 방식으로 커널에서 구동 중인 모든 프로세스의 태스크 디스크립터 주소를 알 수 있습니다. 

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




#프로세스

프로세스 소개 
프로세스 확인하기  
프로세스는 어떻게 생성할까?  
유저 레벨 프로세스 실행 실습  
커널 스레드  
커널 내부 프로세스의 생성 과정   
프로세스의 종료 과정 분석  
태스크 디스크립터(task_struct 구조체)  
스레드 정보: thread_info 구조체  
프로세스의 태스크 디스크립터에 접근하는 매크로 함수  
프로세스 디버깅  
   * glibc의 fork() 함수를 gdb로 디버깅하기  


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

Thanks,
Austin Kim(austindh.kim@gmail.com)


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

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

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


 


핑백

덧글

댓글 입력 영역