[linux] 프로세스란
1. 프로세스란?
- 메모리에서 실행 중인 프로그램
- 스케줄링 대상인 태스크(task)와 유사한 의미로 사용됨
- 커널 함수 이름이나 변수 중에 task가 보이면 프로세스 관련 코드라 생각해도 좋음
리눅스 개발자 입장에서의 프로세스
- 리눅스 시스템 메모리에 적재되어 실행을 대기하거나 실행하는 실행 흐름
- task_struct, thread_info 구조체로 관리됨
PID란?
- 커널이 프로세스를 생성할 때 프로세스에 붙이는 고유의 정수형 ID 값
- 리눅스 커널에서 프로세스가 생성될 때 int 형 ID인 PID를 프로세스에게 알려줌
- 커널은 PID를 증가시키면서 프로세스에 부여
- 유저 공간에서 getpid() 함수를 호출하면 프로세스의 PID를 읽을 수 있다
- 시스템 콜 핸들러인 sys_getpid() 함수가 호출됨
/* https://github.com/raspberrypi/linux/blob/rpi-4.19.y/include/linux/types.h */
typedef __kernel_pid_t pid_t;
/* https://github.com/raspberrypi/linux/blob/rpi-4.19.y/include/uapi/asm-generic/posix_types.h */
typedef int __kernel_pid_t;
리눅스에서 공통으로 생성하는 프로세스의 PID
- swapper 프로세스 : 0
- init 프로세스 : 1
- kthreadd 프로세스 : 2
2. 프로세스는 어떻게 생성할까?
- 리눅스에서 구동 중인 모든 프로세스는 _do_fork() 함수가 실행할 때 생성됨
- 프로세스 생성을 전담하는 프로세스가 있음
- init : 유저 레벨 프로세스 생성 전담, 부팅 과정에서 유저 프로세스를 생성
- kthreadd : 커널 레벨 프로세스(커널 스레드) 생성 전담
- 자식 프로세스는 부모 프로세스를 복제하여 생성됨
- 이미 생성된 프로세스의 리소스를 복제하는 것이 효율적이기 때문
유저 레벨 프로세스 생성 시 _do_fork() 함수의 처리 흐름
- 유저 공간에서 fork() 함수를 호출하면 시스템 콜을 발생시킴
- 커널 공간에서 sys_clone() 함수를 호출
- sys_clone() 함수는 _do_fork() 함수를 호출해 프로세스를 생성
커널 프로세스 생성 시 _do_fork() 함수의 흐름
- 커널 프로세스 : 시스템 콜 없이 커널 함수로 생성되어 커널 공간에서만 실행되는 프로세스
- 1 단계 : kthreadd 프로세스에게 커널 프로세스 생성을 요청
- kthread_create() 함수를 호출해 kthreadd 프로세스에게 커널 프로세스 생성을 요청함. 그리고 kthreadd 프로세스를 깨움
- 2 단계 : 커널 프로세스 생성
- kthreadd 프로세스는 깨어나 자신에게 커널 프로세스 생성 요청을 했는지 점검. 프로세스 생성 요청이 있으면 프로세스를 생성
3. 커널 스레드란?
- 커널 프로세스는 커널 공간에서만 실행되는 프로세스
- 대부분 커널 스레드 형태로 동작
- 리눅스 시스템 프로그래밍에서 데몬과 비슷한 일을 함
- 차이점 : 커널 스레드는 유저 영역과 시스템 콜을 받지 않고 동작
커널 스레드의 종류
- kthreadd 프로세스
- 모든 커널 스레드의 부모 프로세스
- 스레드 핸들러 함수는 kthreadd()이며 커널 스레드를 생성하는 역할을 수행
- 워커 스레드(kworker)
- 워크 큐에 큐잉된 워크를 실행하는 프로세스
- ksoftirqd 프로세스
- Soft IRQ를 위해 실행하는 프로세스
- smp_boot 형태의 스레드이며, 프로세스 이름의 맨 오른쪽에 실행중인 CPU 번호를 볼 수 있음
- irq/86-mmc1 스레드
- IRQ 스레드라 하며, 인터럽트 후반 처리를 위해 쓰이는 프로세스
- [“irq”/”인터럽트 번호”-“인터럽트 이름”]
4. 프로세스의 종료 과정 분석
프로세스는 크게 두 가지 흐름으로 종료된다.
- 유저 애플리케이션에서 exit() 함수를 호출할 때
- 종료 시그널을 전달 받았을 때
- exit() 시스템 콜 실행
- 유저 프로세스가 정해진 시나리오에 따라 종료해야 할 때 exit() 함수를 호출
- 시스템 콜이 발생한 후 해당 시스템 콜 핸들러인 sys_group_exit() 함수가 호출, 이후 do_exit() 함수를 호출
- 종료 시그널을 전달 받았을 때
- 커널 프로세스도 커널 내부에서 종료 시그널을 받으면 종료됨
- 커널 함수로 send_signal() 함수를 호출하면 특정 프로세스에게 종료 시그널을 전달할 수 있음
Reference
디버깅을 통해 배우는 리눅스 커널의 구조와 원리
댓글남기기