vfork()는 SYS_vfork를 호출하지만 fork()는 SYS_clone을 호출합니까?

vfork()는 SYS_vfork를 호출하지만 fork()는 SYS_clone을 호출합니까?

ltrace -S(버전 5.4.0)로 컴파일된 두 개의 프로그램 gcc(하나는 vfork()다른 하나를 호출함) 을 실행한 후 호출이 동시에 호출되는 fork()것을 발견했습니다 . 어디에서나 이 특정 동작에 대한 정보를 찾을 수 없습니다(일부 소스에서는 각각 , 및 가 해당 이름의 호출로 구현된다고 말하고, 다른 소스에서는 세 호출 모두 를 사용하여 구현된다고 말합니다.vfork()SYS_vforkfork()SYS_clonefork()vfork()clone()sys_sys_clone

소스 코드:

#include<stdio.h>
main()
{
        int pid;
        pid=vfork();
}

출력 ltrace -S:

...
__libc_start_main([some stuff here] <unfinished ...>
vfork([more stuff] <unfinished ...>
SYS_vfork([more stuff])
--- SIGCHLD (Child exited) ---

SYS_vforklibc가 for를 사용 vfork() 하지만 for를 사용하지 않는 SYS_fork이유가 있나요 fork()? 나는 읽었다Thomas Nyman의 답변도착하다 커널에서 sys_clone() 시스템 호출을 사용하여 fork(), vfork()를 지정하는 파일은 무엇입니까?, 내용은 다음과 같습니다.

vfork()그 반대는 별도의 플래그를 통해 CLONE_VFORK달성 되며, 이는 하위 프로세스가 신호를 통해 깨어날 때까지 상위 프로세스를 절전 모드로 전환합니다. 자식은 호출되거나 종료될 때까지 부모의 네임스페이스에서 유일한 실행 스레드가 됩니다 exec(). 어린이는 메모리에 쓸 수 없습니다. 해당 clone()호출은 다음과 같습니다.

clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0)

이것은 내가 관찰하고 있는 결과와 일치하지 않는 것 같습니다 ltrace -S.

내가 뭔가를 망친 걸까요, 아니면 glibc 작성자가 어떤 이유로 의도적으로 대신 사용하기로 선택한 vfork()걸까요 ? 이는 언제든지 변경될 수 있는 것으로 간주됩니까, 아니면 신뢰할 수 있습니까?SYS_vforkSYS_clone

답변1

내가 망친 걸까요, 아니면 glibc 작성자가 어떤 이유로 vfork()를 구현하기 위해 의도적으로 SYS_clone 대신 SYS_vfork를 사용하기로 선택했습니까?

vfork역사적으로 볼 때 이는 단지 변경할 필요가 없는 결과 일 가능성이 더 높다고 생각합니다 . vfork처음에는 둘 다 fork동등한 시스템 호출을 사용합니다. NPTL 스레드를 구현할 때,fork사용할 변경사항 구현clone, 왜냐하면C 라이브러리는 스레드 ID를 재설정해야 합니다.. 스레드는 사용 목적으로만 사용되므로 (어차피 모든 상태가 재설정됨) 변경되지 않은 상태로 유지되므로 vfork걱정할 필요가 없습니다 .execve

NPTL 디자인 파일fork스레드를 사용할 수 있는 경우 시스템 호출이 라이브러리 호출을 구현하는 데 충분하지 않은 이유를 설명합니다 .fork

메모리 누수 없이 기능을 구현하기 위해서는 fork스택에서 사용하는 메모리와 스레드 호출을 제외한 모든 스레드의 내부 정보를 회수해야 한다. fork이 상황에서 커널이 할 수 있는 일은 아무것도 없습니다.


이는 언제든지 변경될 수 있는 것으로 간주됩니까, 아니면 신뢰할 수 있습니까?

C 라이브러리를 사용하면 C 라이브러리에서 제공하는 API에 문서화된 동작에만 의존할 수 있으며 특정 구현에는 의존할 수 없습니다. 대신 시스템 호출을 vfork(3)사용 하거나 syscall 대신 syscall을 사용 해서는 안 됩니다 . 사용되는 시스템 호출은 아키텍처마다 다를 수 있습니다.vfork(2)clone(2)fork(3)clone(2)fork(2)

특정 시스템 호출에 정말로 의존해야 한다면 이를 직접 사용하고 C 라이브러리 래퍼를 버려야 합니다.

답변2

man 2 fork:

C 라이브러리/커널 차이점
버전 2.3.3부터 NPTL 스레드 구현의 일부로 제공되는 glibc fork() 래퍼는 커널의 fork() 시스템 호출을 호출하지 않고 대신 동일한 효과를 제공하는 플래그를 사용하여 clone(2)을 호출합니다. 전통적인 시스템 호출. (fork()에 대한 호출은 플래그 SIGCHLD를 지정하는 clone(2)에 대한 호출과 동일합니다.) glibc 래퍼는 pthread_atfork(3)를 사용하여 설정된 모든 포크 핸들러를 호출합니다.

관련 정보