본문 바로가기
IT 기술/리눅스 커널

fork 와 vfork 의 차이점

by 땅뚱 2009. 8. 28.
fork 는 일반적으로 새로운 프로세스를 생성하기 위해서 사용하는 시스템 콜중 하나이다. fork 를 호출한 프로세스를 부모 프로세스라 부르고 fork 에 의해서 생성된 새로운 프로세스를 자식 프로세스라고 부른다.

예전 Unix 에서는 자식 프로세스가 생성되면서 부모 프로세스의 메모리, 파일 기술자 테이블 등을 복사하여 프로세스를 구성하였다. 하지만, 자원을 복사하는 데 걸리는 시간 때문에, 프로세스 생성까지 오랜 시간이 걸렸다. 이러한 단점을 보완하기 위해서 대안으로 만들어진 것이 vfork 이다.

vfork 는 부모 프로세스와 자원을 공유한다. 자원 복사가 이루어지지 않기 때문에 기존 fork 보다 빠르게 프로세스를 생성할 수 있다. 하지만 자원을 공유하기 때문에 자원에 대한 race condition 이 발생하지 않도록 해주기 위해서 부모 프로세스는 자식 프로세스가 exit 하거나 execve 가 호출되기 전까지 block 된다.

아래는 kernel 의 do_fork 함수중 일부이다. vfork 로 do_fork 가 호출된 경우에 wati_for_completion 을 호출하고 block 되는 것을 볼 수 있다.

kernel/fork.c do_fork:
(생략)
1398         if (clone_flags & CLONE_VFORK) {
1399             p->vfork_done = &vfork;
1400             init_completion(&vfork);
1401         }
(생략)
1421         if (clone_flags & CLONE_VFORK) {
1422             wait_for_completion(&vfork);
1423             if (unlikely (current->ptrace & PT_TRACE_VFORK_DONE)) {
1424                 current->ptrace_message = nr;
1425                 ptrace_notify ((PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP);
1426             }
1427         }
(생략)

execve 가 수행되면서 프로세스 구조체에서 wait 중인 프로세스가 있는지 확인하고 있는 경우 complete 를 호출하여 위 코드에서 wait 하고 있던 프로세스를 깨워준다.

fs/exec.c coredump_wait :
(생략)
1447     vfork_done = tsk->vfork_done;
1448     if (vfork_done) {
1449         tsk->vfork_done = NULL;
1450         complete(vfork_done);
1451     }      
1452        
(생략)

exit 이 수행되면서 호출되는 mm_release 를 통해서 wait 중인 프로세스가 있는지 확인하고 complete 를 호출하여 wait 하는 프로세스를 깨워준다.

kernel/fork.c mm_release :
463     struct completion *vfork_done = tsk->vfork_done;
(생략)
469     if (vfork_done) {
470         tsk->vfork_done = NULL;
471         complete(vfork_done);
472     }  

그럼 항상 fork 는 메모리를 복사하기 때문에 프로세스를 생성하기 위해서는 vfork 를 사용해야 하는가 라는 의문이 들 수 있다.

fork 가 항상 메모리를 복사한다는 것은 예전 방식이고, 현재 리눅스에서 fork 는 copy-on-write 기법을 사용하여 프로세스 생성시 모든 자원을 복사하는 것이 아니고 변경사항이 생길 경우에만 복사하도록 구현되어 있다. 따라서 현재 fork 가 갖는 단점은 부모 프로세스의 페이지 테이블을 복사하는 것과 자식 프로세스를 기술하기 위한 프로세스 구조체를 할당받는 시간과 메모리 뿐이다.

vfork 를 사용하는 경우에 execve 를 바로 호출하지 않는 경우라면 자식 프로세스에서 수정한 변수들이 부모 프로세스에 영향을 미칠 수 있기 때문에 주의해서 코딩해야 한다.

참고 사이트
1. http://unius.tistory.com/entry/fork-vs-vfork
2. http://www.unixguide.net/unix/programming/1.1.2.shtml
3. http://book.opensourceproject.org.cn/kernel/kernelpri/opensource/0131181637/ch03lev1sec3.html