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

Rus*_*lan 7 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)
Run Code Online (Sandbox Code Playgroud)

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

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

Ale*_*x D 6

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

看看Linux的实现fork,但是:

return _do_fork(SIGCHLD, 0, 0, NULL, NULL, 0);
Run Code Online (Sandbox Code Playgroud)

这是clone:

return _do_fork(clone_flags, newsp, 0, parent_tidptr, child_tidptr, tls);
Run Code Online (Sandbox Code Playgroud)

显然,它们几乎完全相同.唯一的区别是,在调用时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.
Run Code Online (Sandbox Code Playgroud)

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

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