본문 바로가기

Enginius/Linux

fork() 함수의 동작

 리눅스에서 fork를 통해 프로세스를 생성할때 프로세스를 어떻게 생성하고 어떻게 runqueue에 등록 시키는지 소스를 통해 그 순서를 정리해 보았다.. 아래 sequence diagram은 kernel2.6.24와 arm 기준으로 설명 하고 있으며 중요한 function과 변수에 대해서만 설명하도록 하고 나머지 궁금한 부분은 누가 뭐라 그래도 직접 찾아 보는것이 도움이 될것이라 생각한다. ^^

1 . User Level이든 Kernel Level이든 fork()를 호출 하게 되면 clone() 시스템 호출에 의해 fork.c의 do_fork()을 호출하게 된다.
    1.1 do_fork()에서는 기본적으로 프로세스에 핵심인 task_struc와 thread_info를 만들게 된다. 
         thread_info는 kernel 2.6에서 새로이 추가된 정보로 preemptive kernel을 만들기위한 주요한 역할을 담당한다.

2. sched.c의 sched_fork()는 생성된 task_struct의 변수에 값을 설정하는 부분으로
    2.1 cfs  스케줄을 위해 sched_class에 sched_fair.c에 있는 함수를( &fair_sched_class )를 등록 시키고
    2.2 생성과정에서는 thread_inf.preempt_count = 1로 설정해서 프로세스가 선점될수 없도록 처리( none- preemptive )하고
    2.3 se.on_rq = 0 으로 설정해서 차후 wake_up_new_task() function에서 activate_task()를 호출 할수 있도록 처리하고
    
3. 다시 do_fork()는 arm/kernel에 있는 process.c의 copy_thread()를 호출하고

4. copy_thread()는 어셈블 코드인 ret_from_fork()를 저장한다 ( 어셈블리로 호출 하는 부분을 찾지 못해 살짝 당항했음 ^^ )

5. ret_from_fork()는 sched.c에 있는 sched_tail()함수를 호출하는데

6. sched_tail()함수는 preempt_enable()을 호출하여 생성된 프로세스를 선점 가능하게 변경한다
    6.1 preempt_enable()은 current 의 thread_info.preempt_count를 1 감소함. 즉, 앞 2.2의 preemt_count =1을 0으로 변경하여 
         선점가능한( preemptive ) 프로세서로 만듬

7. wake_up_new_task()는 현재 프로세스의 on_rq가 0이면( 새로 시작하는 프로세스라면.. ) activate_task()를 호출하고

8. activate_task()는 enqueue_task() 호출하며

9. enqueue_task()는 sched_fair.c에 있는 enqueue_task_fair() 함수를 호출 후 task_struct.se.on_rq= 1로 세팅하며 정상적으로 
    실행할수 있는 프로세스임으로 변경하게 된다.

10. 마지막으로 enqueue_task_fair()는 생성된 프로세스에 대한 sched_entity를 rb-tree에 등록한다.