1. wait는 어떻게 process를 rq에서 삭제할까?
이번엔 실행중 인 process가 잠자게( wait )될때 어떻게 runqueue에서 제거 되는지 살펴 보도록 하자실행중인 process를 재우기 위해선 wait 관련 함수( wait_event(), wait_event_timeout(), wait_event_interruptible() , wait_event_interruptible_timeout() )를 사용하게 되는데 여기서 설명하는것은 함수 자체에 대한 설명보다는 이런 함수들이 어떻게 현재의 current를 runqueue에서 제거하는지를 촛점에 맞추었으며 이해를 돕기 위해 wait_event_interruptible()를 기준으로 설명하도록 하겠다.
1. "wait.h" 에 있는 wait_event_interrupt를 호출하게 되면
1.1 DEFINE_WAIT 메크로를 호출하게 되는데. 이 매크로는 process의 wait_queue에 queue의 이름과 current를 등록하게 된다.
또한 func 항목에는 autoremove_wake_function()을 등록하여 차후 wake_up될때 호출 될수 있도록 하고 있다 ( 이부분은
다음 세미나에서 다룰 wake_up 부분에서 다시 한번 설명 하겠다 )
2. 다시 wait_event_interrupt에 돌아 와서 본격적인 busy wait를 처리 하게 되는데
wait_event_interrupt를 호출 할 때 조건이 만족하지 않거나 wak_up signal이 있을때 까지 loop를 돌며
2.1 wait.c에 있는 prepare_to_wait()함수를 호출하게된다.
prepare_to_wait()함수는 현재 process의 wait_queue가 wait_queue_head에 등록 되어 있지 않으면
wait_queue_head list에 등록하고 현재 current의 task_struct 상태를 TASK_INTERRUPTIBLE로 변경 해주는데
이는 차후 실제적으로 runqueue에서 삭제하기 위한 중요한 조건이 된다.
2.2 wake_up signal이 있을 때 까지sched.c 에 있는 scheduler()를 호출하게 되는데 2.1에서 설정한
TASK_INTERRUPTIBLE 때문에 아래 조건에 의해 deactivate_task가 호출 되어면 runqueue에서 제거 되게 된다.
if (unlikely((prev->state & TASK_INTERRUPTIBLE) && unlikely(signal_pending(prev))))
{
prev->state = TASK_RUNNING;
} else {
deactivate_task(rq, prev, 1);
}
2. Wait상태의 process는 어떻게 rq에 등록될까?
잠들어 있던 프로세스가 깨어나는 방법은 다양하다 .. timeout이 된다든지, 어떤 조건( condition )에 만족할 경우라든지 아니면 누군가가 wake_up signal을 직접 보낼때 잠자던 프로세스가 깨어 난다.. 그럼 이때 깨어난 프로세스는 어떻게 다시 runqueue에 등록될까?
이전 강좌에 프로세스를 재우기 위해 wait_event_interruptible() 함수를 사용한 것 처럼 깨우는 함수도 wake_up_interruptible()을 사용하여 설명 하도록 하겠다..
1. 먼저 잠자던 프로세스를 깨우기 위해 wait.h 에 있는 wake_up_interruptible()을 호출 한다.
2. wake_up_interruptible() 함수는 sched.c에 있는 __wake_up() 함수를 호출하고
3. wake_up()함수는 다시 __wake_up_common()함수를 호출 한다.
4.__wake_up_common()함수는 등록된 wait_queue를 하나씩 찾아내며 생성시 등록된 func ( 기억 나겠지 ?? )를 호출하게 되는데
5. 그 함수가 wait.c에 있는 autoremove_wake_function() 이다.
6. autoremove_wake_function()은 다시 sched.c에 있는 default_wake_function()을 호출 하고
정상적으로 처리되면 wait_queue를 삭제하게 된다.
7. default_wake_function()으로 돌아 가서 default_wake_function()는 try_to_wake_up() 함수를 호출 하게 되는데..
8. 바로 이 try_to_wake_up() 함수에서 activate_task()를 호출하여 runqueue에 다시 등록하게 되는것이다.
3. process 종료(exit)
process 종료는 의외로 간단하다. 실제로 소스를 보더라도 몇라인 되지도 않는다.. 간단히 보자..
먼저 process가 종료할게 되면 exit.c의 do_exit()가 호출되어진다.
1. 먼저 task_struct의 flag를 PF_EXITING 으로 자신이 종료 중임을 알린다.
2. __exit_mm()을 통해 process가 가지고 있던 mm_struct 해제 하고
3. ext_sem()를 통해 세마포어 해제
4. __exit_files()를 통해 파일 서술자 참조 카운트 감소
5. __exit_fs()를 통해 파일 시스템 참조 카운트 감소
6. task_struc.state = TASK_DEAD를 설정한 후 sched.c 의 schedule 호출
7. schedule()은 deactivate()함수를 통해 runqueue에서 삭제 한다...
'Enginius > Linux' 카테고리의 다른 글
perf top 사용하기 (0) | 2011.08.01 |
---|---|
DWRR (Distributed weighted round-robin) Scheduler (0) | 2011.08.01 |
fork() 함수의 동작 (0) | 2011.08.01 |
리눅스 스케쥴러의 변천사 O(1), CFS (0) | 2011.08.01 |
O(1) 스케줄러의 문제점과 CFS 스케줄러 (0) | 2011.08.01 |