c - 为什么 glibc 的 fork 实现没有使用 sys_fork?

标签 c linux fork glibc

在eglibc的nptl/sysdeps/unix/sysv/linux/i386/fork.c中有一个定义:

#define ARCH_FORK() \
  INLINE_SYSCALL (clone, 5,                           \
          CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, 0,     \
          NULL, NULL, &THREAD_SELF->tid)

在实际的 __libc_fork() 中用作实现的核心。但是例如在 Linux 的 arch/x86/entry/syscalls/syscall_32.tbl 中存在一个 sys_fork 条目,在 syscalls_64.tbl 中也是如此。所以显然 Linux 确实有它的特殊系统调用 fork

所以我现在想知道:如果内核已经提供了 fork 系统调用,为什么 glibc 会根据 clone 实现 fork()

最佳答案

我查看了 Ulrich Drepper 将该代码添加到 glibc 的提交,但在提交日志(或其他地方)中没有任何解释。

尽管看看 Linux 的 fork 实现:

return _do_fork(SIGCHLD, 0, 0, NULL, NULL, 0);

这里是克隆:

return _do_fork(clone_flags, newsp, 0, parent_tidptr, child_tidptr, tls);

显然,它们几乎完全相同。唯一的区别是调用 clone 时,您可以设置各种标志,可以为新进程指定堆栈大小等。fork 不接受任何参数。

查看 Drepper 的代码,clone 标志是 CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD。如果使用 fork,唯一的标志将是 SIGCHLD

这是 clone 联机帮助页中关于这些额外标志的内容:

CLONE_CHILD_CLEARTID (since Linux 2.5.49)
          Erase child thread ID at location ctid in child memory when  the  child
          exits,  and  do  a  wakeup  on  the futex at that address.  The address
          involved may be changed by the set_tid_address(2) system call.  This is
          used by threading libraries.

CLONE_CHILD_SETTID (since Linux 2.5.49)
          Store child thread ID at location ctid in child memory.

...你可以看到他确实传递了一个指针,指向内核应该首先存储子线程 ID 的位置,然后再进行 futex 唤醒。 glibc 是否正在某处对该地址进行 futex 等待?我不知道。如果是这样,那就可以解释为什么 Drepper 选择使用 clone

(如果没有,那将只是我们心爱的 glibc 的极端积累的又一个例子!如果你想找到一些漂亮、干净、维护良好的代码,请继续前进,看看在 musl libc!)

关于c - 为什么 glibc 的 fork 实现没有使用 sys_fork?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37165339/

相关文章:

linux - logrotate:仅将新的压缩文件移动到 S3

c - setpgid 的竞争条件

C语言: How to share a struct (or,如果不可能,一个数组)通过IPC在父子( fork )进程之间?

c - 为什么 fork() 返回该组合中所有可能的输出?

c - gcc 和 clang 中的 C99 支持不一致

c - 在 c 的 union 中存储值

c - 用 C 绘图

c - Modbus 中的多线程?如何在 500 毫秒内发送查询并将响应时间保持为 1 秒?

python - 使用 doctests 在 Python 项目中导入

linux - 在 RAM 中运行 Vagrant VM 有哪些方法?