프로세스 종료 방식
프로세스 종료 방식은 크게 두 가지로 나뉜다.
1, 유저 프로세스 레벨에서의 Signal 종료
아래 글에서 Signal 방식의 종료에 대하여 ftrace 를 통해 분석하였다.
2022.02.07 - [Embedded/Linux Kernel] - [Linux Kernel] ftrace 를 통한 유저 프로세스 분석
[Linux Kernel] ftrace 를 통한 유저 레벨 프로세스 분석
먼저 유저 프로세스 생성을 위한 raspbian_test.c 파일 이다. #include #include #define PROC_TIMES 500 #define SLEEP_DURATION 3 // second unit int main() { int proc_times = 0; for(proc_times = 0; proc_t..
darkengineer.tistory.com
2. 유저 프로세스 POSIX exit 시스템 콜을 통한 스스로 종료
아래 글에서는 유저 프로세스가 POSIX exit 시스템 콜을 발생하였을 때, 종료 과정을 ftrace 를 통해 분석하였다.
2022.02.16 - [Embedded/Linux Kernel] - [Linux Kernel] ftrace 를 통한 유저 레벨 프로세스 분석(POSIX exit 종료 방식)
[Linux Kernel] ftrace 를 통한 유저 레벨 프로세스 분석(POSIX exit 종료 방식)
프로세스 종료 방식 프로세스 종료 방식은 크게 두 가지로 나뉜다. 1, 유저 레벨에서의 Signal 종료 아래 경로 글에서 Signal 방식의 종료에 대하여 ftrace 를 통해 분석하였다. 2022.02.07 - [Embedded/Linux Ke
darkengineer.tistory.com
프로세스 종료 소스 분석
먼저 프로세스 종료의 공통적인 함수로 do_exit 함수가 있는데, 이 세부 동작은 자세히 알 필요가 있다.
이유는, 실제 Linux 혹은 Custom OS 에서 개발 시 유저 레벨이나 커널 레벨에서 의도치 않게 프로세스
종료로 문제되는 경우가 있다.
do_exit() 함수 분석
do_exit 함수에 대해서는 자세히 알아보겠다. 먼저 ftrace 를 통해 종료 콜 스텍을 확인해 보자.
signal 프로세스 종료 단계의 함수 흐름
do_exit+0x14/0xa90 <-do_group_exit+0x50/0xe0 45892 raspbian_proc-1440 [003] .... 3299.693248: <stack trace> 45893 => do_group_exit+0x50/0xe0 45894 => get_signal+0x17c/0xa34 45895 => do_work_pending+0x460/0x57c 45896 => slow_work_pending+0xc/0x20 45897 => 0xb6e58eac
slow_work_pending -> do_work_pending -> get_signal -> do_group_exit ->do_exit
exit 프로세스 종료 단계의 함수 흐름
__wake_up_parent 를 통해 sys_exit_group 함수가 호출이 되고 do_group_exit 이후 do_exit 흐름으로 이어진다.
__noreturn 키워드는 실행 후 자신을 호출한 함수로 돌아가지 않는다는 것을 뜻한다.
이유는 간단하다. 커널 코드를 실행하는 주인공인 프로세스가 종료되어 당연히 이전 함수로 못돌아 가는 것이다.
do_exit 함수는 프로세스에 대한 리소스 정리 후 do_task_dead 함수를 호출하여 schedule 함수를 실행한다.
즉, 휴면 상태로 들어가게 된다. 이 의미는 do_exit 함수의 시퀀스를 끝까지 다 수행하지 않는다는 것이다.
그래서 __noreturn 키워드를 지정 한 것이다.
더 깊게 들어가면, 왜 프로세스 종료 후 이전 함수로 가지 못할까?
바로, 프로세스는 자신의 스택 메모리 공간을 해제 할 수 없기 때문이다. 프로세스를 소멸하는 동작인
do_exit 함수를 스택 공간에서 실행한다.
그래서 schedule 을 통해 다음에 실행 될 프로세스에서 이전 프로세스를 종료시켜줘 ~ 라고
체크를 해 놓는 것이다. 이를 위해 do_task_dead 와 schedule 까지 실행하는 이유이다.
실행 단계로는
1. init 프로세스가 종료하면 강제 커널 패닉을 유발로 보통 부팅 과정에서 발생함
2. 이미 프로세스가 do_exit 함수의 실행으로 프로세스가 종료되는 도중 do_exit 함수가 재호출되었는지 확인
3. 프로세스 리소스인 파일 디스크립터 , 가상메모리, 시그널 등을 해제
4. 부모 프로세스에게 자신이 종료됨을 알림
5. 프로세스 실행 상태를 task_struct 의 state 필드에 TASK_DEAD 로 변경
6. do_task_dead 호출하여 스케줄링 실행 그러면 안에서 schedule 이 실행된다.
-> 그 결과 task_struct 와 스택 메모리를 해제 한다.
do_task_dead() 함수 분석
set_special_state 함수를 호출해 프로세스의 상태를 DEAD 로 설정 하고, NOFREEZE 로 flat 연산도 적용한다.
여기서 current 는 현재 프로세스의 task_struct 이다. __schedule 함수에 false 인자는 선점형 스케줄링을 실행 하지 않겠다는 의미이다.
schedule() 함수 분석
역시 스케줄링 역활이라 호출되는 함수량이 적지는 않다.
context_switch 함수도 보인다.
여기서 잠시 정리하면,
1. do_exit 함수에서 대부분 자신의 리소스를 커널에게 반납하고, 상태를 DEAD로 변경
2. 컨텍스트 스위칭을 실시
3. 스위칭으로 다음에 실행하는 프로세스는 finish_task_switch 함수에서 이전 DEAD 상태이면 여기서 스택 공간을 해제한다.
결국 프로세스 스케줄링이 진행되므로 당연 컨텍스트 스위칭이 일어나고 다음 프로세스가 대신 죽여준다
finish_task_switch() 함수 분석
함수의 부분으로 이전 프로세스의 DEAD 를 확인 후 stack 공간을 해제한다.
이렇게 프로세스 종료 과정을 소스를 통해 간략하게 나마 알아보았다.
이 내용은 유저 레벨과 커널 레벨에서의 exit or signal 방식의 공통 과정으로 내용은 같다.
결국 프로세스의 리소스를 해제 후 다음 프로세스에게 스케줄링 후 stack 해제는 다음 프로세스 역할인 것이다.
이게 바로 __noreturn 하는 이유 인 것 이다.
'Embedded > Linux Kernel' 카테고리의 다른 글
[Linux Kernel] gcc 컴파일 옵션 (0) | 2022.02.16 |
---|---|
[Linux Kernel] ftrace 를 통한 유저 레벨 프로세스 분석(POSIX exit 종료 방식) (0) | 2022.02.16 |
[Linux Kernel] ftrace 를 통한 유저 레벨 프로세스 분석(Signal 종료 방식) (0) | 2022.02.07 |
[Linux Kernel] 커널 스레드(프로세스) 생성 과정 소스 분석 (0) | 2022.02.07 |
[Linux Kernel] 커널에서의 프로세스 테스크 스레드 이해 (0) | 2022.02.06 |