Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 465 Vote(s) - 3.44 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How does fork() know when to return 0?

#1
Take the following example:

int main(void)
{
pid_t pid;

pid = fork();
if (pid == 0)
ChildProcess();
else
ParentProcess();
}

So correct me if I am wrong, once fork() executes a child process is created. Now going by this [answer][1] fork() returns twice. That is once for the parent process and once for the child process.

Which means that two separate processes come into existence DURING the fork call and not after it ending.

Now I don't get it how it understands how to return 0 for the child process and the correct PID for the parent process.

This where it gets really confusing. This [answer][2] states that fork() works by copying the context information of the process and manually setting the return value to 0.

First am I right in saying that the return to any function is placed in a single register? **Since in a single processor environment a process can call only one subroutine that returns only one value (correct me if I am wrong here).**

**Let's say I call a function foo() inside a routine and that function returns a value, that value will be stored in a register say BAR. Each time a function wants to return a value it will use a particular processor register.** So if I am able to manually change the return value in the process block I am able to change the value returned to the function right?

***So am I correct in thinking that is how fork() works?***


[1]:

[To see links please register here]

[2]:

[To see links please register here]

Reply

#2
The fork system call creates a new process and copies a lot of state from the parent process. Things like the file descriptor table gets copied, the memory mappings and their contents, etc. That state is inside the kernel.

One of the things the kernel keeps track for every process are the values of registers this process needs to have restored at the return from a system call, trap, interrupt or context switch (most context switches happen on system calls or interrupts). Those registers are saved on a syscall/trap/interrupt and then restored when returning to userland. System calls return values by writing into that state. Which is what fork does. Parent fork gets one value, child process a different one.

Since the forked process is different from the parent process, the kernel could do anything to it. Give it any values in registers, give it any memory mappings. To actually make sure that almost everything except the return value is the same as in the parent process requires more effort.
Reply

#3
For each running process, the kernel has a table of registers, to load back when a context switch is made. `fork()` is a system call; a special call that, when made, the process gets a context switch and the kernel code executing the call runs in a different (kernel) thread.

The value returned by system calls is placed in a special register (EAX in x86) that your application reads after the call. When the `fork()` call is made, the kernel makes a copy of the process, and in each table of registers of each process descriptor writes the appropiate value: 0, and the pid.
Reply

#4
You first need to know how multitasking works. It is not useful to understand all the details, but every process runs in some kind of a virtual machine controlled by the kernel: a process has its own memory, processor and registers, etc. There is mapping of these virtual objects onto the real ones (the magic is in the kernel), and there is some machinery that swap virtual contexts (processes) to physical machine as time pass.

Then, when the kernel forks a process (`fork()` is an entry to the kernel), and creates a copy of almost everything in the *parent* process to the *child* process, it is able to modify everything needed. One of these is the modification of the corresponding structures to return 0 for the child and the pid of the child in the parent from current call to fork.

Note: nether say "fork returns twice", a function call returns only once.

Just think about a cloning machine: you enter alone, but two persons exit, one is you and the other is your clone (very slightly different); while cloning the machine is able to set a name different than yours to the clone.
Reply

#5
*How* it works is largely irrelevant - as a developer working at a certain level (ie, coding to the UNIX APIs), you really only need to know *that* it works.

Having said that however, and recognising that curiosity or a need to understand at some depth is generally a good trait to have, there are any number of ways that this *could* be done.

First off, your contention that a function can only return one value is correct as far as it goes but you need to remember that, after the process split, there are actually *two* instances of the function running, one in each process. They're mostly independent of each other and can follow different code paths. The following diagram may help in understanding this:

<!-- language: lang-none -->

Process 314159 | Process 271828
-------------- | --------------
runs for a bit |
calls fork |
| comes into existence
returns 271828 | returns 0

You can hopefully see there that a *single* instance of `fork` can only return one value (as per any other C function) but there are actually multiple instances running, which is why it's said to return multiple values in the documentation.

---

Here's one possibility on how it *could* work.

When the `fork()` function starts running, it stores the current process ID (PID).

Then, when it comes time to return, if the PID is the same as that stored, it's the parent. Otherwise it's the child. Pseudo-code follows:

def fork():
saved_pid = getpid()

# Magic here, returns PID of other process or -1 on failure.

other_pid = split_proc_into_two();

if other_pid == -1: # fork failed -> return -1
return -1

if saved_pid == getpid(): # pid same, parent -> return child PID
return other_pid

return 0 # pid changed, child, return zero

Note that there's a lot of magic in the `split_proc_into_two()` call and it almost certainly won't work that way at all under the covers<sup>(a)</sup>. It's just to illustrate the concepts around it, which is basically:

- get the original PID before the split, which will remain identical for both processes after they split.
- do the split.
- get the current PID after the split, which will be *different* in the two processes.

You may also want to take a look at [this answer][1], it explains the `fork/exec` philosophy.

---

<sup>(a)</sup> It's almost certainly more complex than I've explained. For example, in MINIX, the call to `fork` ends up running in the kernel, which has access to the entire process tree.

It simply copies the parent process structure into a free slot for the child, along the lines of:

sptr = (char *) proc_addr (k1); // parent pointer
chld = (char *) proc_addr (k2); // child pointer
dptr = chld;
bytes = sizeof (struct proc); // bytes to copy
while (bytes--) // copy the structure
*dptr++ = *sptr++;

Then it makes slight modifications to the child structure to ensure it will be suitable, including the line:

chld->p_reg[RET_REG] = 0; // make sure child receives zero

So, basically identical to the scheme I posited, but using data modifications rather than code path selection to decide what to return to the caller - in other words, you'd see something like:

return rpc->p_reg[RET_REG];

at the end of `fork()` so that the correct value gets returned depending on whether it's the parent or child process.

[1]:

[To see links please register here]

Reply

#6
In Linux `fork()` happens in kernel; the actual place is the [`_do_fork` here](

[To see links please register here]

). Simplified, the `fork()` system call could be something like

pid_t sys_fork() {
pid_t child = create_child_copy();
wait_for_child_to_start();
return child;
}

So in the kernel, `fork()` really returns *once*, into the parent process. However the kernel also creates the child process as a copy of the parent process; but instead of returning from an ordinary function, it would synthetically create a new **kernel stack** for the newly created thread of the child process; and then context-switch to that thread (and process); as the newly created process returns from the context switching function, it would make the child process' thread end up returning to user mode with 0 as the return value from `fork()`.

----

Basically `fork()` in userland is just a thin wrapper returns the value that the kernel put onto its stack/into return register. The kernel sets up the new child process so that it returns 0 via this mechanism from its only thread; and the child pid is returned in the parent system call as any other return value from any system call such as `read(2)` would be.
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through