4.8 태스크 디스크립터(task_struct 구조체)
프로세스의 속성 정보를 표현하는 가장 중요한 자료구조는?
→ 태스크 디스크립터를 나타내는 task_struct 구조체
▶ ps -ely : 프로세스 목록
리눅스 시스템에서 구동 중인 프로세스 목록은 프로세스를 관리하는 태스크 디스크립터의 연결 리스트(init_task.tasks)에 접근하여 등록된 프로세스를 출력한다.
1) 프로세스를 식별하는 필드
→ comm은 TASK_COMM_LEN 크기의 배열이며 프로세스 이름을 저장한다.
→ 프로세스 이름들은 태스크 디스크립터를 나타내는 task_struct 구조체의 comm 필드에 접근해서 출력한다.
ex) 디버깅용 코드
현재 실행 중인 프로세스의 태스크 디스크립터 구조체 task_struct 구조체에 접근하는 current 매크로 + 프로세스 이름을 저장하는 comm 필드 -> 다양한 디버깅용 코드 작성 가능
task_struct *p가 깨우려는 프로세스의 태스크 디스크립터
프로세스 이름이 kthreadd인 경우 dump_stack( ) 함수를 호출해 함수 호출 흐름을 커널 로그로 출력
▶ pid : 프로세스를 식별하는 정수형 값
- 프로세스 아이디 : pid_t pid;
- 스레드 그룹 아이디 : pid_t tgid;
2) 프로세스 상태 저장
▶ 태스크 디스크립터에서 프로세스 상태를 관리하는 두 가지 필드
① state : 프로세스 실행 상태
- TASK_RUNNING : CPU 에서 실행 중이거나 런큐에서 대기 상태에 있음
- TASK_INTERRUPTIBLE : 휴면 상태
- TASK_UNINTERRUPTIBLE : 특정 조건에서 깨어나기 위해 휴면 상태로 진입한 상태
② flags : 프로세스 세부 동작 상태와 속성 정보
→ PF_*로 시작하는 매크로 필드를 OR 연산한 결과를 저장
- PF_IDLE : 아이들 프로세스
- PF_EXITING: 프로세스가 종료 중인 상태
- PF_EXITPIDONE : 프로세스가 종료를 마무리한 상태
- PF_WQ_WORKER : 프로세스가 워커 스레드인 경우
- PF_KTHREAD : 프로세스가 커널 스레드인 경우
▶ exit_state : 프로세스 종료 상태를 저장
- EXIT_DEAD
- EXIT_ZOMBIE
- EXIT_TRACE
▶ exit_code : 프로세스의 종료 코드를 저장
3) 프로세스 간의 관계
▶ 프로세스 간의 관계를 나타내는 필드
① struct task_struct *real_parent : 자신을 생성한 부모 프로세스의 태스크 디스크립터 주소 저장
② struct task_struct *parent : 부모 프로세스의 태스크 디스크립터 주소 저장
※ *real_parent와 *parent의 차이점
→ 부모 프로세스가 종료되지 않고 실행 중이면 같음
→ 프로세스 계층 구조에서 지정한 부모 프로세스가 없을 경우 init 프로세스를 부모 프로세스로 변경하면 다름
위와 같이 부모 프로세스가 종료되면 do_exit( ) 함수에서 화살표 방향으로 함수 호출
forget_original_parent( )와 find_new_reaper( )에서 새로운 부모 프로세스 지정
③ struct list_head children : 부모 프로세스가 자식 프로세스를 생성할 때 children 연결 리스트에 자식 프로세스 등록
④ struct list_head sibling : 같은 부모 프로세스로 생성된 프로세스의 연결 리스트 주소 저장
※ children과 sibling 필드의 연결 방식
▶ ps axjf : 부모와 자식 프로세스 관계 확인
rcu_gp, rcu_par_gp, kworker/0, mm_percpu_wq, ksoftirqd/0 프로세스들의 부몸 프로세스는 kthreadd임을 알 수 있다.
※ 부모 프로세스인 kthreadd 입장에서의 태스크 디스크립터
- kthreadd 프로세스 태스크 디스크립터의 children 필드는 연결리스트
- 연결리스트 헤드에 자식 프로세스의 task_struct 구조체의 sibling 필드 주소를 저장
- kworker/0:0H의 입장에서 mm_percpu_wq와 ksoftirpd/0 프로세스는 자신의 sibling 연결 리스트로 이어져 있음
4) 프로세스 연결 리스트
→ task_struct 구조체의 tasks 필드는 list_head 구조체로서 연결 리스트 타입
※ tasks 필드는 언제 init 프로세스의 태스크 디스크립터 필드 중 연결 리스트 타입이 tasks 필드에 등록될까?
▶ copy_process( ) 함수 : 프로세스를 생성할 때 호출
12번째 줄 실행 시 커널로부터 태스크 디스크립터 할당받음
13번째 줄 실ㄹ행 시 init_task.tasks 연결 리스트의 마지막 노드에 현재 프로세스의 task_struct 구조체의 tasks 주소 등록
▶ tasks 필드를 TRACE32로 확인해보기
6번째 줄에서 가리키는 주소의 의미는?
→ init_task.tasks 연결 리스트에 추가된 다음 프로세스의 task_struct 구조체의 tasks 필드 주소
즉, 0xA1618310 주소는 연결 리스트에 등록된 다음 프로세스 태스크 디스크립터의 next 필드 주소를 의미
→ 이 방식으로 커널에서 구동 중인 모든 프로세스의 태스크 디스크립터 주소를 알 수 있음
5. 프로세스 실행 시각 정보
▶ 태스크 디스크립터에서 프로세스의 실행 시각 정보를 알 수 있는 필드
① u64 utime : 유저 모드에서 프로세스가 실행한 시각
② u64 stime : 커널 모드에서 프로세스가 실행한 시각
③ struct sched_info sched_info.last_arrival : 프로세스 스케줄링 정보 저장
※ sched_info.last_arrival 필드는 언제 변경될까?
→ sched_info_arrive( ) 함수의 9번째 줄에서 업데이트됨
※ sched_info_arrive( ) 함수는 언제 호출될까?
→ context_switch( ) 함수 내에서 컨텍스트 스위칭을 수행하기 직전에 prepare_task_switch( ) 함수를 호출하는데, 이 함수를 따라가다 보면 호출됨
다음 순서로 함수 호출 후 실행
• context_switch( )
• prepare_task_switch( )
• sched_info_switch( )
• __sched_info_switch( )
• sched_info_arrive( )
→ 커널은 sched_info_arrive( ) 함수에서 프로세스의 실행 시간을 업데이트함
★ 크래시 유틸리티 프로그램 "ps -l"
→ 가장 마지막에 실행된 순서대로 프로세스 목록 출력
→ 크래시 유틸리티 프로그램 : 커널 크래시를 디버깅할 수 있는 유틸리티 프로그램
- URL: https://people.redhat.com/anderson/crash_whitepaper/
이는 리눅스 커널 개발자들이 자주 활용하는 프로그램이니 잘 알아두기!
4.9 스레드 정보 : thread_info 구조체
1) thread_info 구조체란?
→ 커널에서는 프로세스의 세부 실행 정보를 저장하거나 로딩하는 자료구조가 필요한데, 이를 관리함
▶ 프로세스의 핵심 실행 정보 저장
- 선점 스케줄링 실행 여부
- 시그널 전달 여부
- 인터럽트 컨텍스트와 Soft IRQ 컨텍스트 상태
- 휴면 상태로 진입학 직전 레지스터 세트를 로딩 및 백업
※ thread_info 구조체는 어디에 있을까?
→ 프로세스 스택의 최상단 주소에 위치, 프로세스마다 1개의 구조체가 있음
▶ 프로세스의 세부 실행 정보 저장
- 컨텍스트 정보
- 스케줄링 직전 실행했던 레지스터 세트
- 프로세스 세부 실행 정보
★ task_struct 구조체와 thread_info 구조체의 차이점
- task_struct : CPU 아키텍처에 독립적인 프로세스 관리용 속성을 저장
- thread_info : CPU 아키텍처에 종속적인 프로세스의 세부 속성을 저장
★ thread_info 구조체에서 관리하는 커널의 핵심 동작
- 현재 실행 중인 코드가 인터럽트 컨텍스트인지 여부
- 현재 프로세스가 선점 가능한 조건인지 점검
- 프로세스가 시그널을 받았는지 여부
- 컨텍스트 스케줄링 전후로 실행했던 레지스터 세트를 저장하거나 로딩
'2021 SUMMER STUDY > LINUX KERNEL' 카테고리의 다른 글
Week04_프로세스2 (0) | 2021.08.15 |
---|---|
Week03_프로세스 (0) | 2021.08.09 |
Week02_커널 디버깅과 코드 학습 (0) | 2021.07.25 |
Week01_리눅스 소개와 전망 (0) | 2021.07.18 |