□ 상태 전이(State Transition)와 실행 수준 변화
태스크는 생성된 뒤, 자신에게 주어진 일을 수행하며, 이를 위해 디스크 I/O나 락(Lock)등 CPU 이외의 자원을 요청하기도 한다.
만약 태스크가 당장 제공해 줄 수 없는 자원을 요청한다면 커널은 이 태스크를 잠시 '대기' 하도록 만든 뒤
다른 태스크를 먼저 수행시키며, 태스크가 요청했던 자원이 사용 가능해지면 다시 '수행' 시켜 줌으로써
보다 높은 시스템 활용률을 제공하려 한다. 따라서, 태스크는 상태 전이(state transition)라는 특징을 가지게 된다.
그림에서 EXIT_ZOMBIE와 EXIT_DEAD는 task_struct 구조체의 exit_state 필드에 저장되는 값이며,
그 외의 상태들은 state 필드에 저장된다. 일단, 태스크가 생성되면 그 태스크는 준비 상태(Task_RUNNING)가 된다.
스케줄러는 여러 태스크 중에서 실행시킬 태스크를 선택하여 수행시킨다.
따라서, TASK_RUNNING상태는 구체적으로 준비상태와 실제 CPU를 배정받아 명령어 들을 처리하고 있는 실행상태
이 두 가지로 나뉘게 된다. 즉, n개의 CPU를 갖는 시스템에서는 임의의 시점에 최대 n개의 태스크가 실제 실행 상태에 있을 수 있다.
#TASK_DEAD 상태
- 태스크가 자신이 해야 할 일을 다 끝내고 exit()를 호출 또는 kill 되는 경우 이 상태로 전이된다.
구체적으로는 task_struct 구조체 내에 존재하는 exit_state 값과 조합하여 TASK_DEAD(EXIT_ZOMBIE) 상태로 전이.
#ZOMBIE 상태
- 말 그대로 죽어있는 상태, 태스크에게 할당되어 있던 자원을 대부분 커널에게 반납한 상태이다.
그러나, 자신이 죽은 후 부모 태스크에게 사용한 자원의 통계 정보를 알려주기 위해 유지 되고 있는 상태.
자식상태가 TASK_DEAD 상태로 전이되면 자식 태스크는 자신이 유지하고있던 모든 자원을 반납.
※ 부모 태스크가 먼저죽어 고아태스크가되면 init태스크로 바꾸어 주며 wait()등의 함수를 호출할때 고아태스크는 소멸.
#TASK_RUNNING 상태
- 실제 수행되던 태스크가 자신에게 할당된 CPU시간을 모두 사용하였거나, 보다 높은 우선순위를 가지는 태스크로
인해 준비(TASK_RUNNING(ready))상태로 전환되는 경우.
SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU 등의 시그널을 받은 태스크는 TASK_STOPPED 상태로 전이되며, 추후 SIGCONT 시그널을
받아 다시 TASK_RUNNING(ready) 상태로 전환된다. 한편, 디버거의 ptrace() 호출에 의해 디버깅 되고 있는 태스크는
시그널을 받는 경우 TASK_TRACED 상태로 전이 될 수 있다.
#TASK_INTERRUPTIBLE 상태 (TASK_UNINTER_RUPTIBLE, TASK_KILLABLE) 대기상태.
- 사용중인 시스템 자원을 대기상태.
실행 중인 TASK_RUNNING 상태의 태스크는 실행 권한에 따라 사용자 수준실행상태와 커널 수준 실행상태로 구분 할 수 있다.
사용자 수준 실행 상태는 CPU에서 사용자 수준 프로그램의 제작자가 만든 응용프로그램이나 라이브러리 코드를 수행하고
있는 상태로, 당연히 사용자 수준의 권한으로 동작한다. 반면에, 커널 수준 실행 상태는 CPU에서 커널 코드의 일부분을
수행하고 있는 상태로, 사용자 수준 권한보다는 더 강력한 커널 권한으로 동작.
사용자 수준 실행상태에서 커널 수준 실행 상태로 전이 할 수 있는 방법으로
1. 시스탬 호출 사용
- 호출사용시 커널에 트랩이 걸리고 태스크 상태가 커널 수준으로 전이
2. 인터럽트 발생
- 인터럽트가 걸리면 실행 수중이던 태스크가 사용자 수준에서 동작하고 있었다면, 커널 수준상태로 전이
커널의 인터럽트 처리 루틴으로 제어가 넘어가게 된다.
사용자 수준에서 프로그램이 수행될 때에는 32bit CPU를 기준으로 0~4GB까지의 주소 공간 중 3GB 아래 부분에
스택을 배치하고 수행된다.
태스크가 생성되면 리눅스는 task_struct 구조체와 커널 스택을 할당하게 된다.
태스크 당 할당되는 커널 스택은 thread_union이라 불리며, thread_info 구조체를 포함하고 있다.
이 구조체 안에는 해당 태스크의 task_struct를 가리키는 포인터와, 스케줄링의 필요성 여부를 나타내는 플래그,
태스크의 포맷을 나타내는 exec_domain등의 필드가 존재.
만약 태스크가 시스템 호출 등을 통해 커널 수준 실행 상태로 진입한 뒤, 수행해야 할 일을 모두 마쳤다면,
다시 사용자 수준 실행상태로 복귀하여 수행하던 곳에서부터 다시 작업을 시작해야 할 것이다.
그러기 위해서는 커널과 사용자 수준간의 변화시에 커널 스택 안에 현재 레지스터의 값들을
구조체를 이용하여 저장함으로써 이뤄진다. 그림 상단부 pt_regs라는 이름으로 표시된 공간이 이 목적으로 사용된다.
'Linux > Kernels' 카테고리의 다른 글
태스크(task)관리-(5) (0) | 2016.09.02 |
---|---|
태스크(task)관리-(4) (0) | 2016.09.02 |
리눅스 커널 (0) | 2016.08.31 |
태스크(task)관리-(2) (0) | 2016.08.30 |
태스크(task)관리-(1) (0) | 2016.08.29 |
댓글