Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
354 views
in Technique[技术] by (71.8m points)

c - Is it true that fork() calls clone() internally?

I read in the 3rd chapter of the "Linux Kernel Development, Second Edition" by Robert Love (ISBN:0-672-32720-1) that the clone system call is used to create a thread in Linux. Now the syntax of clone is such that a starting routine/function address is needed to be passed to it.

But then on the same page it is written that fork calls clone internally. So my question is, how do child process created by fork starts running the part of code which is after fork call, i.e. how does it not require a function as starting point?

If the links I provided have incorrect info, then please guide me to some better links/resources.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

For questions like this, always read the source code.

From glibc's nptl/sysdeps/unix/sysv/linux/fork.c (GitHub) (nptl = native Posix threads for Linux) we can find the implementation of fork(), which is definitely not a syscall, we can see that the magic happens inside the ARCH_FORK macro, which is defined as an inline call to clone() in nptl/sysdeps/unix/sysv/linux/x86_64/fork.c (GitHub). But wait, no function or stack pointer is passed to this version of clone()! So, what is going on here?

Let's look at the implementation of clone() in glibc, then. It's in sysdeps/unix/sysv/linux/x86_64/clone.S (GitHub). You can see that what it does is it saves the function pointer on the child's stack, calls the clone syscall, and then the new process will read pop the function off the stack and then call it.

So it works like this:

clone(void (*fn)(void *), void *stack_pointer)
{
    push fn onto stack_pointer
    syscall_clone()
    if (child) {
        pop fn off of stack
        fn();
        exit();
    }
}

And fork() is...

fork()
{
    ...
    syscall_clone();
    ...
}

Summary

The actual clone() syscall does not take a function argument, it just continues from the return point, just like fork(). So both the clone() and fork() library functions are wrappers around the clone() syscall.

Documentation

My copy of the manual is somewhat more upfront about the fact that clone() is both a library function and a system call. However, I do find it somewhat misleading that clone() is found in section 2, rather than both section 2 and section 3. From the man page:

#include <sched.h>

int clone(int (*fn)(void *), void *child_stack,
          int flags, void *arg, ...
          /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ );

/* Prototype for the raw system call */

long clone(unsigned long flags, void *child_stack,
          void *ptid, void *ctid,
          struct pt_regs *regs);

And,

This page describes both the glibc clone() wrapper function and the underlying system call on which it is based. The main text describes the wrapper function; the differences for the raw system call are described toward the end of this page.

Finally,

The raw clone() system call corresponds more closely to fork(2) in that execution in the child continues from the point of the call. As such, the fn and arg arguments of the clone() wrapper function are omitted. Furthermore, the argument order changes.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...