Through appropriate system calls, such as fork or spawn, processes may create other processes. The process which creates other process, is termed the parent of the other process, while the created sub-process is termed its child.
Each process is given an integer identifier, termed as process identifier, or PID. The parent PID (PPID) is also stored for each process.
On a typical UNIX systems the process scheduler is termed as
sched, and is given PID 0. The first thing done by it at system start-up time is to launch
init, which gives that process PID 1. Further Init launches all the system daemons and user logins, and becomes the ultimate parent of all other processes.
A child process may receive some amount of shared resources with its parent depending on system implementation. To prevent runaway children from consuming all of a certain system resource, child processes may or may not be limited to a subset of the resources originally allocated to the parent.
There are two options for the parent process after creating the child :
- Wait for the child process to terminate before proceeding. Parent process makes a
wait()system call, for either a specific child process or for any particular child process, which causes the parent process to block until the
wait()returns. UNIX shells normally wait for their children to complete before issuing a new prompt.
- Run concurrently with the child, continuing to process without waiting. When a UNIX shell runs a process as a background task, this is the operation seen. It is also possible for the parent to run for a while, and then wait for the child later, which might occur in a sort of a parallel processing operation.
There are also two possibilities in terms of the address space of the new process:
- The child process is a duplicate of the parent process.
- The child process has a program loaded into it.
To illustrate these different implementations, let us consider the UNIX operating system. In UNIX, each process is identified by its process identifier, which is a unique integer. A new process is created by the fork system call. The new process consists of a copy of the address space of the original process. This mechanism allows the parent process to communicate easily with its child process. Both processes (the parent and the child) continue execution at the instruction after the fork system call, with one difference: The return code for the fork system call is zero for the new(child) process, whereas the(non zero) process identifier of the child is returned to the parent.
By making the
exit(system call), typically returning an int, processes may request their own termination. This int is passed along to the parent if it is doing a
wait(), and is typically zero on successful completion and some non-zero code in the event of any problem.
Processes may also be terminated by the system for a variety of reasons, including :
- The inability of the system to deliver the necessary system resources.
- In response to a KILL command or other unhandled process interrupts.
- A parent may kill its children if the task assigned to them is no longer needed i.e. if the need of having a child terminates.
- If the parent exits, the system may or may not allow the child to continue without a parent (In UNIX systems, orphaned processes are generally inherited by
init, which then proceeds to kill them.)
When a process ends, all of its system resources are freed up, open files flushed and closed, etc. The process termination status and execution times are returned to the parent if the parent is waiting for the child to terminate, or eventually returned to init if the process already became an orphan.
The processes which are trying to terminate but cannot do so because their parent is not waiting for them are termed zombies. These are eventually inherited by init as orphans and killed off.