[linux] 프로세스란

2 분 소요

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() 함수의 처리 흐름

do_fork

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

커널 프로세스 생성 시 _do_fork() 함수의 흐름

kernel_threadd

  • 커널 프로세스 : 시스템 콜 없이 커널 함수로 생성되어 커널 공간에서만 실행되는 프로세스
  • 1 단계 : kthreadd 프로세스에게 커널 프로세스 생성을 요청
    • kthread_create() 함수를 호출해 kthreadd 프로세스에게 커널 프로세스 생성을 요청함. 그리고 kthreadd 프로세스를 깨움
  • 2 단계 : 커널 프로세스 생성
    • kthreadd 프로세스는 깨어나 자신에게 커널 프로세스 생성 요청을 했는지 점검. 프로세스 생성 요청이 있으면 프로세스를 생성

3. 커널 스레드란?

  • 커널 프로세스는 커널 공간에서만 실행되는 프로세스
  • 대부분 커널 스레드 형태로 동작
  • 리눅스 시스템 프로그래밍에서 데몬과 비슷한 일을 함
    • 차이점 : 커널 스레드는 유저 영역과 시스템 콜을 받지 않고 동작

커널 스레드의 종류

  • kthreadd 프로세스
    • 모든 커널 스레드의 부모 프로세스
    • 스레드 핸들러 함수는 kthreadd()이며 커널 스레드를 생성하는 역할을 수행
  • 워커 스레드(kworker)
    • 워크 큐에 큐잉된 워크를 실행하는 프로세스
  • ksoftirqd 프로세스
    • Soft IRQ를 위해 실행하는 프로세스
    • smp_boot 형태의 스레드이며, 프로세스 이름의 맨 오른쪽에 실행중인 CPU 번호를 볼 수 있음
  • irq/86-mmc1 스레드
    • IRQ 스레드라 하며, 인터럽트 후반 처리를 위해 쓰이는 프로세스
    • [“irq”/”인터럽트 번호”-“인터럽트 이름”]

4. 프로세스의 종료 과정 분석

프로세스는 크게 두 가지 흐름으로 종료된다.

  1. 유저 애플리케이션에서 exit() 함수를 호출할 때
  2. 종료 시그널을 전달 받았을 때

do_exit

  • exit() 시스템 콜 실행
    • 유저 프로세스가 정해진 시나리오에 따라 종료해야 할 때 exit() 함수를 호출
    • 시스템 콜이 발생한 후 해당 시스템 콜 핸들러인 sys_group_exit() 함수가 호출, 이후 do_exit() 함수를 호출
  • 종료 시그널을 전달 받았을 때
    • 커널 프로세스도 커널 내부에서 종료 시그널을 받으면 종료됨
    • 커널 함수로 send_signal() 함수를 호출하면 특정 프로세스에게 종료 시그널을 전달할 수 있음

Reference
디버깅을 통해 배우는 리눅스 커널의 구조와 원리

태그:

카테고리:

업데이트:

댓글남기기