(1) 상태 전이와 실행 수준 변화

태스크는 생성 뒤 자신에게 주어진 일을 수행하며, 이를 위해 디스크 I/O나 락 등 CPU이외의 자원을 요청

 

특정 태스크가 당장 제공해 줄 수 없는 자원을 요청한다면?

1. 커널은 이 task를 잠시 '대기' 하도록 만듬

2. 다른 태스크를 먼저 수행

3. 태스크가 요청한 자원이 사용 가능해 지면 대기상태의 태스크를 다시 '수행'

 

 

□ EXIT_ZOMBIE 상태

- 말 그대로 죽어있는 상태. Task에게 할당되어 있던 자원을 대부분 커널에게 반납한 상태.

- 자신이 종료된 이유를 부모 태스크에게 알려주기 위해 유지 되고 있는 상태

 

□ EXIT_DEAD 상태

- 부모 Task가 wait()을 호출하면 자식 태스크의 상태가 EXIT_DEAD로 바뀜

- 부모는 자식의 종료 정보를 넘겨받고 자식태스크는 자신이 유지하던 자원을 모두 반환하고 최종 종료됨

 * 부모 task의 wait()함수 호출 전 먼저 사라지게 되면 고아 태스크가 영원히 존재해 시스템의 오버헤드로 작용됨

     --> 이 문제를 해결하기 위해 커널은 고아 task의 부모를 init task로 바꾸어줌 (task_struct 구조체에 real_parent와 parent 2개의 필드가 존재하는 이유)

 

□  TASK_RUNNING 상태

- 실제 수행중인 task의 상태 (running)과 수행되던 task가 자신에게 할당된 CPU 시간을 모두 사용하여 다시 준비중인 상태 (ready)

 

□  TASK_INTERRUPTIBLE 상태

- 실행 상태에 있던 태스크가 특정한 사건을 기다려야 할 대기상태로 전환되어 기다리는 사건에 따라 특정 큐(queue)에 매달려 대기중인 상태

- 대기하는 동안 자신이 기다리는 그 사건 외에는 일체 방해받아선 안 되는 경우가 있을 수 있는데 이 경우가 TASK_UNINTERRUPTIBLE.

- 이후 기다리던 사건 발생 시 대기 상태에 있던 TASK가 다시 준비(ready)상태로 전이하게 되며 다시 다른 태스크들과 함께 스케줄링 되기 위해 경쟁함.

  * TASK_UNINTERRUPTIBLE 상태의 Task가 시그널에 반응하지 않기때문에 생기는 문제

     -> (예> 쉘에서 'kill -9 pid' 등의 명령을 수행해도 태스크가 종료되지 않음)

         => 이를 해결하기 위해 TASK_KILLABLE 상태가 도입

 

(2) TASK_RUNNING(running) 상태의 수준

- 실제로 실행중인 TASK_RUNNING(running) 상태는 다시 사용자 수준 실행 상태와 커널 수준 실행 상태로 구분할 수 있음

 

□ 사용자 수준 실행 (user level running)

- CPU에서 사용자 수준 프로그램의 제작자가 만든 프로그램이나 라이브러리 함수를 수행하고 있는 상태로 사용자 수준의 권한으로 동작

 

□ 커널 수준 실행 (kernel level running)

- CPU에서 커널 프로그램의 일부분을 수행하고 있는 상태로, 사용자 수준 권한보다는 더 강력한 커널 수준 권한으로 동작

 

* 사용자 수준에서 커널수준 실행상태로 전이하는 방법

  1. 시스템 호출

  2. 인터럽트 발생

 

(3) 커널 수준의 프로그램

- 커널 수준의 프로그램은 바로 리눅스 그 자체임

- 리눅스도 C와 어셈블리어로 작성된 S/W이기 때문에 수행되기 위해서는 스택을 필요로 함

 

 

- 리눅스 커널은 태스크가 생성될 때마다 태스크 별로 task_struct 구조체와 8KB의 스택을 할당해 줌

- 8KB의 스택은 thread_union이라 불림, thread_info(프로세스 디스크립터) 구조체도 포함 되어있음.

-Pt_regs는 수행을 마친 task가 사용자 수준 실행상태로 복귀하기 이전 수행 작업에 대한 정보 저장 

+ Recent posts