How Does Fork() Return for Child Process

How does fork() return for child process

% man fork

RETURN VALUES

Upon successful completion, fork() returns a value of 0 to the child
process and returns the process ID of the child process to the parent
process. Otherwise, a value of -1 is returned to the parent process, no
child process is created, and the global variable [errno][1] is set to indi-
cate the error.

What happens is that inside the fork system call, the entire process is duplicated. Then, the fork call in each returns. These are different contexts now though, so they can return different return codes.

If you really want to know how it works at a low level, you can always check the source! The code is a bit confusing if you're not used to reading kernel code, but the inline comments give a pretty good hint as to what's going on.

The most interesting part of the source with an explicit answer to your question is at the very end of the fork() definition itself -

if (error == 0) {
td->td_retval[0] = p2->p_pid;
td->td_retval[1] = 0;
}

"td" apparently holds a list of the return values for different threads. I'm not sure exactly how this mechanism works (why there are not two separate "thread" structures). If error (returned from fork1, the "real" forking function) is 0 (no error), then take the "first" (parent) thread and set its return value to p2 (the new process)'s PID. If it's the "second" thread (in p2), then set the return value to 0.

Why fork() return 0 in the child process?

As to the question you ask in the title, you need a value that will be considered success and cannot be a real PID. The 0 return value is a standard return value for a system call to indicate success. So it is provided to the child process so that it knows that it has successfully forked from the parent. The parent process receives either the PID of the child, or -1 if the child did not fork successfully.

Any process can discover its own PID by calling getpid().

As to your update question, it seems a little backward. Any process can discover its parent process by using the getppid() system call. If a process did not track the return value of fork(), there is no straight forward way to discover all the PIDs of its children.

How does fork return a Pid?

under the hood fork looks something as following:

int fork() {
1. generate a new PID for child // executed only by parent process
2. do million more things required to create a process // executed only by parent
/* now we have a new process in the system, which can be scheduled on CPU */
3. finally return value of a specific CPU register // executed by both parent and child
// Note that at this point we have two processes,
// in case of child process the CPU register contains 0 (fork returns 0 to child)
// in case of parent process register contains PID of child
}

So as you can see fork in parent process doesn't have to wait for child in order to return the child's PID, as it was already available to parent process.

where is fork's child process return value?

System calls are executed by the process' context who called them. That means the process who called them will receive the system call function return value. The fork implementation has the same behavior as all other system calls but is a bit special because 2 processes supposly return from it although only the parent process actually called it.

The child process's stack is being built to simulate a system call was previously made, together with it's simulated return value stored in the trapframe's eax register (which used for holding the function return value).

When the child process is selected to run by the scheduler, it's first line of code that run will be the forkret function and trapret as the simulated stack was prepared by allocproc function.

What does fork() == 0 returns?

fork creates a new process as an identical copy of the process that calls it. And it returs twice. Once in the original caller (the parent process) with the PID of the newly created child and once in the newly create child with 0.

So if you do if (fork() == 0) { ... }, the code inside the if body will run in the newly created child.

Don't do that however, as the parent does need to know the PID of the child because it has to wait for it.

How does the fork() know whether it is in child process and in parent process?

When fork() is called, a process spawns a child process with shared or duplicated process segments. What that means is that in a program, before fork() is called, there is only one process, or one unit of execution. After fork() returns, there are two processes running concurrently. Since both processes have the same call stack at this point, it looks to each processes as if it had just called fork(). In the parent process, the return value of fork() is the PID of the child process. In the child process, the return value of fork() is 0.

You can see this with a really simple demonstration:

#include <unistd.h>
#include <stdio.h>

int main(){
pid_t parent = getpid();
pid_t child = fork();

if(child != 0){
printf("I am the parent process. My PID is %d\n", parent);
printf("Parent process terminating\n");
}
else{
printf("I am the child process. My PID is %d\n", getpid());
printf(" My parent's PID is %d\n", parent);
printf("Child process terminating\n");
}
return 0;
}

Here's a sample run on my laptop:

$ gcc -o fork fork.c
$ ./fork
I am the parent process. My PID is 16048
Parent process terminating
I am the child process. My PID is 16049
My parent's PID is 16048
Child process terminating
$

Note that when you run this, the PIDs will be different. Also, the output is subject to a race condition, so sometimes, the parent process will return to the shell before the child process finished printing, so it might look like this:

$ ./fork
I am the parent process. My PID is 16265
Parent process terminating
$ I am the child process. My PID is 16266
My parent's PID is 16265
Child process terminating

What's important to understand is that fork() causes the single process of execution to split into two independent units. Since each process is still spawned from the same program (or source code), the behaviour is the same for both processes. The reason their output differs is only due to the fact that fork() returns different values for parent or children processes.

fork() returns 0, but the child process getpid()!=0. Why?


the child process shows I am the child with pid 25111. I thought the child process pid should be 0

No. In the parent fork() returns the pid of the child. In the child, fork returns 0 -- which is not the pid of anything, it's just a marker. The child pid is 25111, as getpid told you.

with the parent process, fork returned 25111, but getpid() returns 25110

Right. The parent pid was always 25110, as getpid told you. And fork() returned the pid of the new child.

The fact that fork returned the same value in the parent as getpid returned in the child proves that this is all working properly.

It sounds like you think fork() always returns the pid of the process that you're in. But that wouldn't make sense -- we already have the getpid call for that.

If you're the parent, fork() returns the pid of the other process, the child. And if you're the child, fork() doesn't return a pid at all. (If you're the child and you want to know the pid of your parent, that's a good, frequent, and separate question. Answer: call getppid().)

We can summarize all this as follows:

                 parent   child
------ -----
pid: 25110 25111
fork returns: 25111 0
getpid returns: 25110 25111
getppid returns: ????? 25110

The way to remember this is to think about the code that's going to be calling fork(): what it's going to do, what it needs to know. The parent needs to know that it is the parent. The child needs to know that it is the child. The parent very often needs to know the pid of the child (and would have no other way of obtaining it).

If fork always returned a pid, then after the fork call, looking at its return value, you would have no way of knowing whether you were the parent or the child -- but this is typically the first and most important thing you need to know.

(In all of this I've ignored the third possibility, namely that fork fails, and returns -1 in the parent, and doesn't return anything in the child, because there isn't one.)

See also Why fork() return 0 in the child process? .



Related Topics



Leave a reply



Submit