On the above link what is meant by
do_fork() which creates a new process ?
Let's start by looking at the raw system call interface. It varies a bit by architecture, but on x86-64 it is:
long clone(unsigned long flags, void *child_stack, int *ptid, int *ctid, unsigned long newtls);
ctid are your
child_tidptr. Now let's see what the
clone(2) manual page has to say:
CLONE_CHILD_CLEARTID (since Linux 2.5.49) Erase the child thread ID at the location ctid in child memory when the child exits, and do a wakeup on the futex at that address. CLONE_CHILD_SETTID (since Linux 2.5.49) Store the child thread ID at the location ctid in the child's memory. CLONE_PARENT_SETTID (since Linux 2.5.49) Store the child thread ID at the location ptid in the parent's memory.
These flags were primarily designed to implement threading libraries. If we take a look at the NPTL implementation of
pthread_create() inside glibc, we eventually find code in
sysdeps/unix/sysv/linux/createthread.c that makes a
clone() call that includes
clone() call, we can also see that the
ctid arguments point to the same address. (Remember that POSIX threads share an address space; this is accomplished with the
So, what's going on here is the following.
CLONE_PARENT_SETTIDis being used to ensure that the kernel thread ID is being stored in a certain location in user space. The user-space side of the threading implementation needs to know that thread ID.
CLONE_CHILD_CLEARTIDis being used to clear (i.e., zero) that same location when the thread created by
Let's go a little further...
The thread ID that is returned via
ctid is not the same as a POSIX thread ID (
pthread_t), although in the 1:1 threading implementations such as NPTL, there is a one-to-one correspondence between kernel thread IDs and POSIX thread IDs. The kernel thread ID is the same ID you get by using the Linux
gettid() call. It's also returned by
clone() as the system call return value, which prompts the question: why do we need
ctid? The problem is that from the user-space side, things look like this:
tid = clone(...);
From the point of view of the user-space threading implementation, there's a race here, because the assignment to
tid occurs only after
clone() returns. This means that the user-space threading library may run into certain problems if it wants that information before the new thread does anything (like terminate, for example). Using
CLONE_PARENT_SETTID ensures that the new thread ID is placed in the location pointed to by
clone() returns, and thus allows a threading library to avoid such race conditions. (
CLONE_CHILD_SETTID can also be used to similar effect.)
The reason that
CLONE_CHILD_CLEARTID is used to clear the
ctid is to provide a way for a
pthread_join() call in another thread to discover that the thread has terminated. In essence, the
ctid location is being used as a futex, and the
futex() system call is used to block, waiting for the integer at this location to change. (The details are a little convoluted, but
grep for uses of
lll_futex_wait in the glibc source code. Ultimately, there is a
FUTEX_WAIT operation taking place. Recall above that
CLONE_CHILD_CLEARTID does a futex wakeup on the target address.)
tid stands for "thread id". The parameters
child_tidptr point to user space memory in the parent process address space and child process address space, respectively. The newly created thread's id is stored in the int variables the pointers point to.
For more information, see the