vfork() 调用 SYS_vfork 但 fork() 调用 SYS_clone?

use*_*462 1 linux glibc linux-kernel ltrace

在运行ltrace -S由gcc(版本 5.4.0)编译的两个程序后,一个调用vfork(),一个调用fork(),我发现vfork()调用SYS_vforkwhilefork()调用SYS_clone。我找不到任何有关这个特定的行为在任何地方的任何信息(有消息说各的fork(),vfork()并且clone()由相应的命名来实现sys_通话,而其他消息来源说,所有的三个电话使用实施sys_clone)。

源代码:

#include<stdio.h>
main()
{
        int pid;
        pid=vfork();
}
Run Code Online (Sandbox Code Playgroud)

输出ltrace -S:

...
__libc_start_main([some stuff here] <unfinished ...>
vfork([more stuff] <unfinished ...>
SYS_vfork([more stuff])
--- SIGCHLD (Child exited) ---
Run Code Online (Sandbox Code Playgroud)

libc 使用SYS_vforkforvfork() 但不使用SYS_forkfor是否有原因fork()?我读过托马斯·尼曼的回答到 哪个文件在内核指定fork()的一样,vfork()...在使用sys_clone()系统调用,它说:

vfork()反过来是通过一个单独的CLONE_VFORK标志实现的,这将导致父进程休眠,直到子进程通过信号唤醒它。子进程将是父进程命名空间中唯一的执行线程,直到它调用exec()或退出。不允许孩子写入内存。相应的clone()调用可能如下:

clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0)

这似乎与我观察到的ltrace -S.

我是不是搞砸了什么,还是 glibc 的作者故意选择实现vfork()usingSYS_vfork而不是SYS_clone出于某种原因?这被认为是可以随时改变的东西还是我们可以依赖它?

Ste*_*itt 5

我是不是搞砸了什么,还是 glibc 的作者出于某种原因故意选择使用 SYS_vfork 而不是 SYS_clone 来实现 vfork() ?

从历史上看,我认为这更有可能只是vfork不需要更改的结果。无论vfork和fork最初使用等效系统调用。当NPTL线程开始实施,将fork实现改为使用clone,因为C库需要重置线程ID。vfork不需要担心线程,因为它仅用于与execve(无论如何都会重置所有状态),因此它保持不变。

NPTL 设计论文解释了为什么在可能使用线程时fork系统调用不足以实现fork库调用:

为了实现fork没有内存泄漏的功能,需要fork回收用于除线程调用之外的所有线程的堆栈和其他内部信息的内存。在这种情况下,内核无能为力。


这被认为是可以随时改变的东西还是我们可以依赖它?

由于您使用 C 库进行 fork,因此您只能依赖 C 库提供 API 中记录的行为;您不能依赖特定的实现。您不应该依赖vfork(3)使用vfork(2)系统调用代替clone(2),也不应该依赖fork(3)使用clone(2)代替fork(2)。请注意,使用的系统调用可能因一种架构而异...

如果你真的需要依赖特定的系统调用,你应该直接使用那些并放弃 C 库包装器。