Linux Kernel(4.19) Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

130199
1107
135858


[리눅스커널] 프로세스: 유저 레벨 프로세스를 생성할 때 _do_fork() 함수의 처리 흐름 4. 프로세스(Process) 관리

이번에는 시야를 넓혀 유저 레벨 프로세스를 생성할 때의 전체 처리 과정을 살펴보겠습니다. 그림 4.2는 유저 레벨 프로세스가 어떤 흐름으로 생성되는지 나타낸 것입니다.

 
그림 4.2 유저 프로세스의 생성 흐름도

보다시피 유저 공간에서 fork() 함수를 호출하면 리눅스에서 제공하는 라이브러리의 도움을 받아 커널에게 프로세스 생성 요청을 합니다. 리눅스에서 제공하는 라이브러리 코드가 실행되면서 시스템 콜을 발생시키고, 리눅스 커널 계층에서는 fork() 함수에 대응하는 시스템 콜 핸들러인 sys_clone() 함수를 호출합니다. 

sys_clone() 함수 분석

유저 공간에서 fork() 함수를 호출하면 커널 공간에서 실행되는 sys_clone() 함수의 코드를 봅시다.

https://elixir.bootlin.com/linux/v4.19.30/source/kernel/fork.c
1 #ifdef __ARCH_WANT_SYS_CLONE
2 #ifdef CONFIG_CLONE_BACKWARDS
3 SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
4 int __user *, parent_tidptr,
5 unsigned long, tls,
6 int __user *, child_tidptr)
...
7 #endif
8 {
9 return _do_fork(clone_flags, newsp, 0, parent_tidptr, child_tidptr, tls);
10 }
11 #endif
---
앞의 코드에서 sys_clone이라는 함수의 이름이 보이지 않는데 필자는 sys_clone() 함수라고 설명했습니다. 커널에서 제공하는 SYSCALL_DEFINE5 매크로와 함께 함수 이름을 지정하면 커널 소스를 빌드하는 과정에서 지정한 함수 이름 앞에 'sys_' 접두사를 붙여서 심벌을 생성합니다. 즉, 다음과 같이 시스템 콜 함수를 정의하면 sys_clone() 시스템 콜 함수가 생성됩니다.

3 SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,

세부 동작은 11장 '시스템콜'의 11.6절을 참고하세요. 
---

9 번째 줄 코드와 같이 sys_clone() 함수는 _do_fork() 함수를 그대로 호출합니다.

유저 레벨에서 생성한 프로세스와 스레드를 커널은 동등하게 처리합니다. 그러니 sys_clone() 함수를 호출하는 것입니다.

유저 레벨 프로세스를 생성할 때의 처리 흐름은 다음과 같이 정리할 수 있습니다.

유저 공간에서 fork() 함수를 호출하면 시스템 콜을 발생시킴
커널 공간에서 sys_clone() 함수를 호출
sys_clone() 함수는 _do_fork() 함수를 호출해 프로세스를 생성 

이 내용을 처음 읽는 독자 분은 이해하기가 쉽지 않을 것입니다. 하지만 4.9절 ‘디버깅’에서 소개한 실습 과정을 따라하면 익숙해질 것입니다. 유저 레벨 프로세스에서 fork() 함수를 호출하면 어떤 과정으로 시스템 콜을 발생시켜 sys_clone() 커널 함수를 호출하는지 알 수 있기 때문입니다. 

비슷한 역할을 수행하는 sys_fork()와 sys_vfork() 시스템 콜 함수를 확인해 봅시다.

https://elixir.bootlin.com/linux/v4.19.30/source/kernel/fork.c
1 SYSCALL_DEFINE0(fork)
2 {
3 #ifdef CONFIG_MMU
4 return _do_fork(SIGCHLD, 0, 0, NULL, NULL, 0);
5 #else
6 /* can not support in nommu mode */
7 return -EINVAL;
8 #endif
9 }
10
11 SYSCALL_DEFINE0(vfork)
12 {
13 return _do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0,
14 0, NULL, NULL, 0);
15 }

sys_fork()와 sys_vfork() 함수도 역시 _do_fork() 함수를 그대로 호출합니다. 

그런데 유저 공간(리눅스 시스템 프로그래밍)에서 fork() 함수로 프로세스를 생성하면 시스템 콜 핸들러로 sys_clone() 함수를 호출합니다. 예전 리눅스 커널 버전에서는 fork() 함수를 호출하면 커널 공간에서 sys_fork() 함수를 호출했으나 최근 리눅스 커널에서는 sys_clone() 함수를 실행합니다. vfork() 시스템 콜 함수도 fork() 시스템 콜을 개선하기 위해 이전 리눅스 커널 버전에서 썼던 레거시(과거) 코드입니다.

다음 절에서는 커널 레벨 프로세스를 생성할 때 do_fork() 함수를 어떻게 실행하는지 살펴보겠습니다.


#프로세스

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


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

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








핑백

덧글

댓글 입력 영역