Linux Kernel(4.19) Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

138199
1107
135866


[리눅스커널] 프로세스: _do_fork() 함수 4. 프로세스(Process) 관리

_do_fork() 함수의 동작은 크게 2단계로 분류할 수 있습니다. 

1단계: 프로세스 생성
copy_process() 함수를 호출해서 프로세스를 생성합니다. copy_process() 함수는 이름에서 볼 수 있듯이 부모 프로세스의 리소스를 자식 프로세스에게 복제합니다. 

2단계: 생성한 프로세스의 실행 요청
copy_process() 함수를 호출해 프로세스를 만든 후 wake_up_new_task() 함수를 호출해서 프로세스를 깨웁니다. 프로세스를 깨운다는 의미는 스케줄러에게 프로세스 실행 요청을 하는 것입니다.

_do_fork() 함수의 전체 흐름을 알아봤으니 _do_fork() 함수의 소스코드를 분석해 봅시다.

https://elixir.bootlin.com/linux/v4.19.30/source/kernel/fork.c
01 long _do_fork(unsigned long clone_flags,
02       unsigned long stack_start,
03       unsigned long stack_size,
04       int __user *parent_tidptr,
05       int __user *child_tidptr,
06       unsigned long tls)
07 {
08 struct completion vfork;
09 struct pid *pid;
10 struct task_struct *p;
11 int trace = 0;
12 long nr;
...
13
14 p = copy_process(clone_flags, stack_start, stack_size,
15 child_tidptr, NULL, trace, tls, NUMA_NO_NODE);
16 add_latent_entropy();
17
18 if (IS_ERR(p))
19 return PTR_ERR(p);
20
21 trace_sched_process_fork(current, p);
22
23 pid = get_task_pid(p, PIDTYPE_PID);
24 nr = pid_vnr(pid);
...
25 wake_up_new_task(p);
...
26 put_pid(pid);
27 return nr;
28 }

먼저 14번째 줄을 봅시다.

14 p = copy_process(clone_flags, stack_start, stack_size,
15 child_tidptr, NULL, trace, tls, NUMA_NO_NODE);

copy_process() 함수를 호출해 부모 프로세스의 메모리 및 시스템 정보를 자식 프로세스에게 복사합니다. 

다음으로 18번째 줄의 조건문을 보겠습니다.
18 if (IS_ERR(p))
19 return PTR_ERR(p);

18번째 줄에서 p라는 포인터형 변수에 오류가 있는지 검사합니다. 만약 태스크 디스크립터의 주소를 담고 있는 p 포인터 변수에 오류가 있으면 19번째 줄과 같이 오류 코드를 반환하면서 함수의 실행을 종료합니다. 태스크 디스크립터에 오류가 없으면 21~27번째 줄의 코드가 실행됩니다.

21~24번째 줄을 봅시다.

21 trace_sched_process_fork(current, p);
22
23 pid = get_task_pid(p, PIDTYPE_PID);
24 nr = pid_vnr(pid);

21번째 줄은 ftrace 이벤트 중 sched_process_fork를 활성화했을 때 동작합니다. '프로세스 생성' 동작을 나타내는 sched_process_fork 이벤트에 대한 메시지는 다음과 같습니다. 

01 kthreadd-2 [003] .... 3495.071381: sched_process_fork: comm=kthreadd pid=2 child_comm=kthreadd child_pid=17193

이 메시지를 보고 “pid가 2인 kthread 프로세스가 pid가 17193인 프로세스를 생성한다”로 해석할 수 있습니다.

다음으로 23~24번째 줄을 봅시다.

23 pid = get_task_pid(p, PIDTYPE_PID);
24 nr = pid_vnr(pid);

여기서는 pid를 계산해서 nr 지역변수에 저장합니다. 정수형 타입인 nr 변수는 프로세스의 pid이며 _do_fork() 함수가 실행을 종료한 후 반환합니다.

다음으로 25번째 줄을 보겠습니다.

25 wake_up_new_task(p);

생성한 프로세스를 깨우는 동작입니다.

이제 마지막 27번째 줄을 보겠습니다.

27 return nr;

프로세스의 PID를 담고 있는 정수형 타입의 nr 지역변수를 반환합니다. 프로세스의 PID를 반환하는 동작입니다.

_do_fork() 함수를 분석하면서 다음과 같은 내용을 알게 됐습니다.

copy_process() 함수를 호출해 프로세스를 생성
wake_up_new_task() 함수를 호출해 생성한 프로세스를 깨움
생성한 프로세스 PID를 반환

다음 절에서는 프로세스 생성 동작의 핵심인 copy_process() 함수를 분석하겠습니다.


#프로세스

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


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

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









 


    핑백

    덧글

    댓글 입력 영역