1. 도입
지난 글에서 Block 되어있던 Task가 새로운 run-queue로 들어오면서 virtual runtime이 어떻게 조정되는지에 대해서 살펴보았다. process state diagram을 살펴보면 다음과 같이 'ready'상태 즉 run queue로 들어오는 경우는 wake_up 말고도 'admitted'인 경우도 있다.
즉, 새로운 process가 생성되는 경우, unix, linux등에서 "Fork" system call이 발생하였을 때 새로운 process(task)의 vruntime은 어떻게 설정될까? 아마 wake_up과 비슷하게 진행되지 않을까 예상되지만 일단 한번 살펴보자.
2. Fork시 code flow따라가기
(1) _do_fork
fork가 발생하면서 _do_fork라는 함수가 호출되고 새로운 process를 만드는 copy_process를 호출한다. 새로 만들어진 process의 vruntime이 어떻게 설정되는지 따라가 보자.
(2) copy_process
copy_process는 매우 큰 함수이다. task_struct안에 있는 수많은 구조체들의 값들을 복사해주고, link를 걸어주는 작업을 거친다. 우리가 현재 관심 있는 부분은 scheduler에 관련된 부분으로 sched_fork라는 함수를 따라 더 들어간다.
(3) sched_fork
sched_fork함수의 앞부분에 재밌는 것들이 많다. 정확히 모든 조건문, flag의 역할을 설명한 책이라도 있었으면 좋겠지만... 대충 유추해보면 state를 TASK_NEW로 설정하고, 부모의 priority를 물려받으며, 만약 sched_reset_on_fork라는 인자가 켜져 있다면, NICE값이 0인 priority로 자동 설정되는 것 같다. 이후 runqueue로 들어갈 cpu를 정하고 이제 task_fork라는 method를 호출하게 되는데, 앞의 "wake up"과 마찬가지로 우리는 task_fork_fair를 호출하게 된다.
(4) task_fork_fair
천천히 살펴보자. cfs_rq->curr는 현재 돌고 있는 task를 가리킨다. update_curr로 인해 curr의 vruntime, cfs_rq의 min_vruntime도 update가 되었을 것이다. 즉, 더 이상 curr의 vruntime이 min_vruntime이 아닐 수 있다. 이러한 상황에서 se->vruntime, 새로 만든 process의 vruntime을 curr->vruntime과 동일하게 만들어준다. 다음 place_entity를 호출하는데 이번에는 인자로 1을 넘겨준다. 앞에서 place_entity는 살펴봤으니 간단히 설명하면 대충 min_vruntime과 curr->vruntime 중 더 큰 것을 se->vruntime에 할당해준다. 다시 task_fork_fair의 밑으로 내려가서 curr와 se의 vruntime을 swap 한다? entity_before라는 함수가 curr와 se를 비교해주는데 curr의 vruntime이 더 작으면, 즉 priority가 더 높으면 이를 바꿔준다. child를 먼저 실행시켜주기 위해서..? 마지막으로 새로 만든 process의 vruntime을 normalize 한다. 마치 block 된 상태로 만들어주는 것 같다.
앞에서 살펴본 흐름을 흐름도로 표현하면 다음과 같다.
여기서 왼쪽에 해당하는 flow가 살펴본 것이고. _do_fork를 더 살펴보면 밑에 'wake_up_new_task'라는 함수를 호출한다. 이 함수를 따라가면 앞에서 봤던 activate_task 함수가 나오고 앞에서 normalized 되어 있던 새로운 process를 실제 cpu의 runqueue에 올리는 enqueue_entity가 나온다. wake_up의 경우 이때 flag값이 ENQUEUE_WAKEUP이어서 place_entity가 실행되었지만 여기서는...
위와 같이 renormalize의 과정을 거친다. current task라면 normalize를 하고 update를 하며, current task가 아니면 current task를 update 한 뒤 normalize를 한다.
3. 궁금증
살펴본 것을 토대로 유추해보면, run_queue를 빠져나가면서 normalization이 발생한다. normalization은 해당 vruntime에서 run queue의 min_vruntime을 빼는 것이다. min_vruntime은 가장 적은 vruntime의 값임으로 현재 돌고 있는 task의 vruntime을 저장하고 있는 것이 아닌가..? 그렇다면 block 된다는 것은 방금까지 running이었다는 것인데 그럼 block된 task의 vruntime은 모두 0인 것인가? 하지만 생각해보면 update_curr의 함수가 언제 호출되냐에 따라서 block시의 normalized 된 값은 약간 다를 수 있을 것 같다. 나중에 block시의 vruntime에 대해 추적해봐야겠다.
(+위의 자료는 리눅스 커널을 공부하기 시작한 지 한 달 조금 된 사람의 개인적인 조사로... 매우 부정확한 정보가 많을 것입니다)
'리눅스' 카테고리의 다른 글
Device Control Method (0) | 2021.04.21 |
---|---|
Cross Development Environment(교차 개발 환경) (0) | 2021.03.12 |
[linux kernel] CFS Scheduler에서 VR(T) 조정(wake_up) (0) | 2021.02.19 |
리눅스 커널에 System Call 추가하기 (0) | 2021.02.08 |
Linux Kernel build_환경 구축(2) (0) | 2021.01.27 |