프로세스 수명 지도

fork는 복제, exec는 교체, wait는 종료 상태 회수다

외부 명령 실행의 대표 경로는 부모가 자식을 만들고, 자식이 같은 PID에서 프로그램 이미지를 바꾸며, 부모가 wait로 결과를 읽어 커널 기록을 지우는 흐름이다.

부모
prepare 인자, 파이프, 리다이렉션을 정리한다.
fork 호출 자식 PID를 받아 부모 흐름을 계속 유지한다.
wait 회수 자식 종료 상태를 읽고 좀비를 제거한다.
자식
0 반환 자식 분기에서는 PID 대신 0을 받아 분기한다.
exec image 현재 주소 공간을 새 프로그램 이미지로 교체한다.
exit status 종료 코드와 시그널 정보를 커널에 남긴다.
커널
COW + FD table 메모리와 파일 디스크립터 참조를 복제한다.
스케줄링 부모와 자식이 독립 실행 흐름으로 번갈아 돈다.
status reap wait가 읽을 수 있도록 종료 상태를 보관한다.
부모 자식 커널 prepare fork wait child PID exec image COW + FD table status reap
01 부모

명령과 실행 환경 준비

셸은 인자, 파이프, 리다이렉션, 환경 변경을 정리한 뒤 외부 명령이면 자식 생성을 준비한다.

02 커널

fork가 두 실행 흐름을 만든다

부모는 자식 PID를 받고, 자식은 0을 받는다. 실패하면 -1만 반환되고 자식은 만들어지지 않는다.

03 자식

exec 전 설정을 끝낸다

리다이렉션, close-on-exec, 환경 변수, 시그널 처리처럼 새 프로그램에 넘길 조건을 이 틈에서 조정한다.

04 자식

exec가 이미지와 엔트리를 바꾼다

성공하면 기존 코드로 돌아오지 않는다. PID는 유지되고 FD_CLOEXEC가 없는 파일 디스크립터는 이어진다.

05 부모

waitpid가 waitable 상태를 회수한다

부모는 먼저 waitpid로 블록될 수 있고, 자식 종료 뒤 반환되며 status를 읽고 좀비 기록을 제거한다.

부모 경로

자식 PID를 보관하고 종료 상태를 읽는다

반환값 양수면 생성된 자식 PID, -1이면 생성 실패다.
foreground 보통 waitpid를 호출해 자식이 끝날 때까지 블록된다.
status WIFEXITED, WEXITSTATUS, WIFSIGNALED, WTERMSIG로 결과를 해석한다.
자식 경로

exec 실패 경로를 반드시 닫는다

반환값 0이면 자식 분기다. 부모 코드로 흘러가지 않게 즉시 나눈다.
FD FD 테이블은 복제되고 같은 open file description을 가리킬 수 있다.
실패 exec가 -1로 돌아오면 perror 후 _exit(127) 같은 경로로 끝낸다.
zombie

종료됐지만 아직 reap되지 않은 기록

child exitZ 상태wait 필요

코드와 스택은 사라졌지만 종료 status와 PID 항목이 남는다. 장기 서버는 SIGCHLD에서 waitpid(-1, ..., WNOHANG)를 반복한다.

orphan

살아 있는 자식보다 부모가 먼저 사라짐

parent exitreparentinit/subreaper

현재 PID namespace의 init 또는 가장 가까운 subreaper가 입양한다. 컨테이너 PID 1은 reaping 책임을 피할 수 없다.

exec fail

새 이미지로 바뀌지 못한 자식

exec -1errno_exit(127)

exec 성공은 반환하지 않는다. 다음 줄이 실행되면 실패 경로이므로 부모 로직을 다시 타지 않게 바로 종료한다.

COW는 주소 공간 복제 비용을 늦춘다

fork 직후 물리 메모리 전체를 즉시 복사하는 것이 아니라, 쓰기가 발생한 페이지부터 실제 복사가 일어난다.

exec는 스케줄링 상태 전이가 아니다

Ready, Running, Waiting 같은 CPU 스케줄링 모델과 달리 exec는 같은 프로세스 안의 프로그램 이미지 교체다.

wait는 관찰이 아니라 정리 동작이다

종료 코드 확인과 함께 프로세스 테이블의 최소 기록을 제거하므로, 서버와 PID 1 역할 프로세스에서 필수다.