- The ps command also lists for each process,
its parent process ID (PPID), i.e., the ID of the process
that started this process. Note that you can follow the chain
of process invocations back to the mother of all processes,
called init. This is the process that runs first
when you bring up UNIX. It then gives rise to all the
processes that you see in your session.
- The UNIX system calls getpid() and getppid()
give information about the current process's PID and its
parent's PID. For instance, if we compile the following
program (showpid.c):
#include <stdio.h>
main()
{
printf("My pid = %d. My parent's pid = %d\n", getpid(), getppid());
}
and run it, say twice, we get:
My pid = 7424. My parent's pid = 2590
My pid = 7425. My parent's pid = 2590
Note that the parent PID is the same but the given process
ID changes on each invocation (why?)
- The pstree command gives a nice tree-structured
list of who started who, revealing the root process as
init.
- To understand how init started everything, we
have to study a concept called "forking". When a process
forks, it is creating a new process which is a copy of itself,
i.e., it copies all its memory stack, variables, open files,
and hands over the copy to the "child" process. At this point,
the child is free to go its own way and do something different.
We can learn about forking by using the UNIX system call
fork() in a C program (simpfork1.c):
#include <stdio.h>
main()
{
int i;
printf("simpfork: pid = %d\n", getpid());
i = fork();
printf("Did a fork. It returned %d. getpid = %d. getppid = %d\n",
i, getpid(), getppid());
}
The first printf is executed before the process
forked, so only one line of output will be generated.
The second printf is executed in both the
parent and the child, so two lines of output are given.
How can you figure out which line was the output of the
child and which came from the parent? You cannot assume,
by default, that the child (or the parent) will be the
first. You have to look at the return values of
fork(). For the parent, it returns the ID of
the child process. For the child, it returns zero.
This is how you know which process you are in when fork()
returns.
- Here's another fork program. After forking,
the parent exits. In such a case, notice who "adopts" the
child process now.
#include <stdio.h>
main()
{
int i;
i = fork();
if (i == 0) {
printf("Child. getpid() = %d, getppid() = %d\n", getpid(), getppid());
sleep(5);
printf("After sleeping. getpid() = %d, getppid() = %d\n",
getpid(), getppid());
} else {
printf("Parent exiting now\n");
}
}
- To reinforce that the parent's address space is truly
copied over to the child, and that these become separate
copies henceforth, try the following program:
#include <stdio.h>
int K;
main()
{
int i;
int j;
j = 200;
K = 300;
printf("Before forking: j = %d, K = %d\n", j, K);
i = fork();
if (i > 0) { /* Delay the parent */
sleep(1);
printf("After forking, parent: j = %d, K = %d\n", j, K);
} else {
j++;
K++;
printf("After forking, child: j = %d, K = %d\n", j, K);
}
}