The signature of the fork is simplicity itself:
pid_t fork(void);
This looks trivial, but you know the saying the devil lies in the details! Indeed, we shall bring out several subtle, and not-so-subtle, pointers regarding the correct usage of this system call.
To begin to understand how fork works, lets write a simple C program (ch10/fork1.c):
int main(int argc, char **argv)
{
fork();
printf("Hello, fork. ");
exit (EXIT_SUCCESS);
}
Build and run it:
$ make fork1
gcc -Wall -c ../../common.c -o common.o
gcc -Wall -c -o fork1.o fork1.c
gcc -Wall -o fork1 fork1.c common.o
$ ./fork1
Hello, fork.
Hello, fork.
$
The fork will, on success, have created a new child process.
This cannot be overstressed.
OK, let's modify the code to check for the failure case; any and every system call (with perhaps just two exceptions out of around 380 syscalls) return -1 on failure. Check for it; here is the relevant code snippet (ch10/fork1.c):
if (fork() == -1)
FATAL("fork failed! ");
printf("Hello, fork. ");
exit(EXIT_SUCCESS);
The output is identical to what we saw previously (of course, since the fork did not fail). So, the printf seems to have been executed twice. Indeed it was: once by the parent process, and once by the new child process. This immediately teaches us something about the way fork works; here, we will attempt to codify these things as the rules of fork. In this book, we shall end up codifying seven rules of fork(2).