커널에서 어떤 파일이 sys_clone () 시스템 호출을 사용하도록 fork (), vfork ()…를 지정하는지


9

ltrace를 사용하여 시스템 호출을 추적하면 fork ()가 sys_fork () 대신 sys_clone ()을 사용한다는 것을 알 수 있습니다. 그러나 리눅스 소스가 정의되어있는 곳을 찾을 수 없었습니다.

내 프로그램은

#include<stdio.h>
main()
{
        int pid,i=0,j=0;
        pid=fork();
        if(pid==0)
                printf("\nI am child\n");
        else
                printf("\nI am parent\n");

}

그리고 ltrace 출력은

SYS_brk(NULL)                                                                               = 0x019d0000
SYS_access("/etc/ld.so.nohwcap", 00)                                                        = -2
SYS_mmap(0, 8192, 3, 34, 0xffffffff)                                                        = 0x7fe3cf84f000
SYS_access("/etc/ld.so.preload", 04)                                                        = -2
SYS_open("/etc/ld.so.cache", 0, 01)                                                         = 3
SYS_fstat(3, 0x7fff47007890)                                                                = 0
SYS_mmap(0, 103967, 1, 2, 3)                                                                = 0x7fe3cf835000
SYS_close(3)                                                                                = 0
SYS_access("/etc/ld.so.nohwcap", 00)                                                        = -2
SYS_open("/lib/x86_64-linux-gnu/libc.so.6", 0, 00)                                          = 3
SYS_read(3, "\177ELF\002\001\001", 832)                                                     = 832
SYS_fstat(3, 0x7fff470078e0)                                                                = 0
SYS_mmap(0, 0x389858, 5, 2050, 3)                                                           = 0x7fe3cf2a8000
SYS_mprotect(0x7fe3cf428000, 2097152, 0)                                                    = 0
SYS_mmap(0x7fe3cf628000, 20480, 3, 2066, 3)                                                 = 0x7fe3cf628000
SYS_mmap(0x7fe3cf62d000, 18520, 3, 50, 0xffffffff)                                          = 0x7fe3cf62d000
SYS_close(3)                                                                                = 0
SYS_mmap(0, 4096, 3, 34, 0xffffffff)                                                        = 0x7fe3cf834000
SYS_mmap(0, 4096, 3, 34, 0xffffffff)                                                        = 0x7fe3cf833000
SYS_mmap(0, 4096, 3, 34, 0xffffffff)                                                        = 0x7fe3cf832000
SYS_arch_prctl(4098, 0x7fe3cf833700, 0x7fe3cf832000, 34, 0xffffffff)                        = 0
SYS_mprotect(0x7fe3cf628000, 16384, 1)                                                      = 0
SYS_mprotect(0x7fe3cf851000, 4096, 1)                                                       = 0
SYS_munmap(0x7fe3cf835000, 103967)                                                          = 0
__libc_start_main(0x40054c, 1, 0x7fff47008298, 0x4005a0, 0x400590 <unfinished ...>
fork( <unfinished ...>
SYS_clone(0x1200011, 0, 0, 0x7fe3cf8339d0, 0)                                               = 5967
<... fork resumed> )                                                                        = 5967
puts("\nI am parent" <unfinished ...>
SYS_fstat(1, 0x7fff47008060)                                                                = 0
SYS_mmap(0, 4096, 3, 34, 0xffffffff
)                                                        = 0x7fe3cf84e000
I am child
SYS_write(1, "\n", 1
)                                                                       = 1
SYS_write(1, "I am parent\n", 12)                                                           = -512
--- SIGCHLD (Child exited) ---
SYS_write(1, "I am parent\n", 12I am parent
)                                                           = 12
<... puts resumed> )                                                                        = 13
SYS_exit_group(13 <no return ...>
+++ exited (status 13) +++


@ mauro.stettler 나는 lxr에서 그것을 찾을 수
없었습니다

1700 행의 git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/… 을 의미 합니까? 무엇을 찾기를 바랐습니까?
msw

답변:


29

glibc 의 fork()vfork()래퍼는 clone()시스템 호출을 통해 구현됩니다 . 더 나은 사이의 관계를 이해하기 위해 fork()그리고 clone(), 우리는 리눅스에서 프로세스와 스레드 사이의 관계를 고려해야합니다.

전통적으로 fork()상위 프로세스가 소유 한 모든 자원을 복제하고 하위 프로세스에 사본을 할당합니다. 이 접근 방식은 상당한 오버 헤드를 발생 시키며, 이는 자식이 즉시 호출하면 모든 것이 아무 것도 아닙니다 exec(). 리눅스에서 fork()분류기는 에 쓰기 - 복사 지연 페이지를 놓거나 부모와 자식 프로세스간에 공유 할 수있는 데이터를 복사하지 마십시오. 따라서, 정상 동안 발생하는 유일한 오버 헤드 fork()는 부모의 페이지 테이블을 복사 task_struct하고 자식에 대한 고유 한 프로세스 설명자 구조체를 할당 하는 것입니다.

리눅스는 또한 스레드에 대한 뛰어난 접근 방식을 취합니다. Linux에서 스레드는 일부 프로세스를 다른 프로세스와 공유하는 일반적인 프로세스 일뿐입니다. 이것은 프로세스와 스레드가 완전히 다른 종류의 짐승 인 Windows 또는 Solaris와 같은 다른 운영 체제와 비교하여 스레드에 대한 근본적으로 다른 접근 방식입니다. Linux에서 각 스레드는 task_struct주소 공간과 같은 특정 리소스를 상위 프로세스와 공유하는 방식으로 설정되는 자체 고유 한 방식을 가지고 있습니다.

시스템 호출 의 flags매개 변수는 clone()상위 및 하위 프로세스가 공유해야하는 자원을 표시하는 플래그 세트를 포함합니다. 프로세스와 스레드는 둘 다 통해 생성되며 clone()유일한 차이점은 전달 된 플래그 집합입니다 clone().

법선 fork()은 다음과 같이 구현 될 수 있습니다.

clone(SIGCHLD, 0);

그러면 부모와 리소스를 공유하지 않는 작업이 생성되고 SIGCHLD종료시 부모에게 종료 신호를 보내도록 설정 됩니다.

반대로, 주소 공간, 파일 시스템 리소스, 파일 설명자 및 신호 처리기를 부모와 공유하는 작업, 즉 스레드 는 다음과 같이 만들 수 있습니다.

clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0);

vfork()차례로 별도의 CLONE_VFORK플래그 를 통해 구현 되므로 자식 프로세스가 신호를 통해 깨울 때까지 부모 프로세스가 절전 모드로 전환됩니다. 자식은 호출 exec()하거나 종료 될 때까지 부모의 네임 스페이스에서 유일한 실행 스레드가 됩니다. 아이는 메모리에 쓸 수 없습니다. 해당 clone()통화는 다음과 같습니다.

clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0)

구현 sys_clone()은 아키텍처에 따라 다르지만 대부분의 작업은에 do_fork()정의되어 kernel/fork.c있습니다. 이 함수는 static을 호출하여 clone_process()부모의 사본으로 새 프로세스를 작성하지만 아직 시작하지는 않습니다. clone_process()레지스터를 복사하고, PID를 새 작업에 할당하고, 복제에 의해 지정된대로 프로세스 환경의 적절한 부분을 복제하거나 공유합니다 flags. clone_process()반환 되면 do_clone()새로 생성 된 프로세스를 깨우고 실행되도록 예약합니다.


2
+1 clone()실과 포크와 관련 하여 의의에 대한 좋은 설명 .
goldilocks

1
내 모든 의심을 해결
user3539

2

Linux에서 userland 시스템 호출 기능을 커널 시스템 호출로 변환하는 책임은 libc입니다. GLibC에서 NPTL 라이브러리는 이것을 clone(2)시스템 호출로 리디렉션합니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.