简体   繁体   English

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

[英]Why is sys_fork not used by glibc's implementation of fork?

In eglibc's nptl/sysdeps/unix/sysv/linux/i386/fork.c there's a definition: 在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)

which is used in actual __libc_fork() as the heart of the implementation. 在实际的__libc_fork()作为实现的核心。 But eg in Linux's arch/x86/entry/syscalls/syscall_32.tbl exists a sys_fork entry, as well as in syscalls_64.tbl . 但是例如在Linux的arch/x86/entry/syscalls/syscall_32.tbl存在一个sys_fork条目,以及syscalls_64.tbl So apparently Linux does have its special syscall for fork . 显然Linux确实有它的特殊系统调用fork

So I now wonder: why does glibc implement fork() in terms of clone , if the kernel already provides the fork syscall? 所以我现在想知道:为什么glibc在clone方面实现fork() ,如果内核已经提供了fork系统调用?

I looked at the commit where Ulrich Drepper added that code to glibc, and there wasn't any explanation in the commit log (or elsewhere). 我查看了Ulrich Drepper将该代码添加到glibc的提交,并且在提交日志(或其他地方)中没有任何解释。

Have a look at Linux's implementation of fork , though: 看看Linux的fork实现,但是:

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

And here is clone : 这是clone

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

Obviously, they are almost exactly the same. 显然,它们几乎完全相同。 The only difference is that when calling clone , you can set various flags, can specify a stack size for the new process, etc. fork doesn't take any arguments. 唯一的区别是,在调用clone ,您可以设置各种标志,可以为新进程指定堆栈大小等fork不接受任何参数。

Looking at Drepper's code, the clone flags are CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD 查看Drepper的代码, clone标志是CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD . CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD If fork was used, the only flag would be SIGCHLD . 如果使用fork ,唯一的标志是SIGCHLD

Here is what the clone manpage says about those extra flags: 以下是关于那些额外标志的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.

...And you can see that he does pass a pointer to where the kernel should first store the child's thread ID and then later do a futex wakeup. ...你可以看到他确实传递了一个指针,指向内核应该首先存储孩子的线程ID,然后再进行futex唤醒。 Is glibc doing a futex wait on that address somewhere? glibc做某个futex在那个地址等吗? I don't know. 我不知道。 If so, that would explain why Drepper chose to use clone . 如果是这样,那就解释了为什么Drepper选择使用clone

(And if not, it would be just one more example of the extreme accumulation of cruft which is our beloved glibc! If you wanted to find some nice, clean, well-maintained code, just keep moving and go have a look at musl libc!) (如果没有,它只是我们心爱的glibc的极端积累的另一个例子!如果你想找到一些漂亮,干净,维护良好的代码,只需继续前进,看看musl libc !)

In a nutshell: why not? 简而言之:为什么不呢?

You have one syscall that is guaranteed to exist on all platforms (you do realize that Intel isn't the only platform out there, right?), and another that is deprecated because it is unnecessary. 你有一个确保在所有平台上存在的系统调用(你确实意识到英特尔不是那里唯一的平台,对吗?),另一个被弃用,因为它是不必要的。 They both carry the exact same semantics. 它们都带有完全相同的语义。 Your code is much more compact when you only call the one guaranteed to exist. 当您只调用保证存在的代码时,您的代码会更加紧凑。

I will elaborate on that a little. 我会详细说明一点。

Fork is defined by Posix, while clone is Linux specific. Fork由Posix定义,而clone是特定于Linux的。 However, Linux, on occasion, takes Posix defined "system calls" and implements them in user space. 但是,Linux有时会将Posix定义为“系统调用”并在用户空间中实现它们。 Such is the case for fork (and vfork and pthread_create). fork(和vfork和pthread_create)就是这种情况。 They are all implemented in user space by calling "clone". 它们都是通过调用“clone”在用户空间中实现的。

As such, fork is deemed unnecessary at the kernel level. 因此,在内核级别认为fork是不必要的。 If a thin user space wrapper can implement it, the kernel is okay with that. 如果瘦用户空间包装器可以实现它,内核就可以了。 As such, on Linux , clone is guaranteed to exist on all platforms, while fork may or may not exist, depending on specific platform. 因此, 在Linux上 ,克隆保证存在于所有平台上,而fork可能存在也可能不存在,具体取决于特定平台。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM