Process A process is an instance of a running program. It consists of virtual registers, virtual memory (stack, heap, global variables) and open file descriptors


PCB To access accounting information of a process in Linux, a Process Control Block (PCB) is the right choice. It contains process state, CPU registers, scheduling information, memory management information, I/O status information and any other type of accounting information. Each process gets a unique pid to keep track of its PCB.


StateDiagram Here is a diagram of the workflow of a process.

In the start phase, a process will be created through forking by its parent process. It is then scheduled by the operating systems for when to run for the first time. By the way there is a lot of scheduling algorithms in use.

Usually, a running process may come straight to the Waiting State when it has used up its CPU time allocated at the time. It will be placed back to the waiting queue to be scheduled again by the operating system.

The process will be blocked when it needs some resources unavailable at the moment being requested. For example, it waits for an I/O operation such as disk reading/writing to complete. There are also other types of blocking operations that are listed below. 1. Acquiring unavailable resources (waits til the resources are free) 2. Synchronization (waits til synchronization is done i.e. locks are released and available for use) 3. Waiting for a signal or event (waits for a child process to terminate for example) 4. Waiting for a timer to expire (sleep function in many languages does this)


Creation On Windows systems, a process is created by loading the program into memory and creating its corresponding Process Control block.

Things are different in Linux. Process are not created from scratch but rather cloned from an existing process, called the parent process. The existing process will be paused execution and all its information, including the PCB, will be re-used for its child. The child, after spawning, may choose to modify its PCB and run another program.

APIs Now we have learned the way to create a process. Next up is how we actually create one in code (C language). To create a process, an api, called as fork, is used.

int fork(void);
/* Returns the process ID of the newly created child process
-1: on Failure
0: in the child process
>0: in the parent process */

Here is an example code snippet to distinguish child and parent processes.

int main(){
	int pid = fork();
 
	if (-1 == pid)
		return -1;
	
	if (0 == pid){
		//do something in the child process
	}else{
		//do something in the parent process
	}
	return 0;
}
 

The execve C wrapper call is a handy tool when it comes to loading a new program in a process. It has following APIs.

nametypedefinition
pathnamea C-style stringthe path name of the binary executable
argvan array of C-style stringsthe arguments passed to the executable
envpan array of C-style stringsthe environment variables passed into the executable
// Declaration of execve
int execve(const char *_pathname_, char *const _Nullable _argv_[],char *const _Nullable _envp_[]);
/*
Returns an error code on failure, does not return if successful
*/

Example code snippet

int main(int argc, char *argv[]) {  
	printf("I'm going to become another process\n");  
	char *exec_argv[] = {"ls", NULL};  
	char *exec_envp[] = {NULL};  
	int exec_return = execve("/usr/bin/ls", exec_argv, exec_envp); 
	if (exec_return 􏰀􏰁 -1) {
		exec_return = errno; 
		perror("execve failed"); return exec_return;
	}  
	printf("If execve worked, this will never print\n"); 
	return 0;
}

StateLookup We may use the following command to check the status of a process

/proc/<PID>/status | grep State
 
# replace <PID> with your actual pid
# -----------------------------------------------
# R: Running and runnable [Running and Waiting] 
# S: Interruptible sleep [Blocked]  
# D: Uninterruptible sleep [Blocked]  
# T: Stopped
# Z: Zombie

ProcessStructure As we’ve said, processes are spawned from an existing process. This implies that there is at least an oldest process at the root to spawn secondary processes.

But how does the first process get created ? It does not have any parent. Well, after initialization, the kernel creates a process from a program. This process is called init and it can be found at /sbin/init. This process is responsible for executing every other process on the machine. Also, It must stay active to make the kernel think you are not shutting down.

Below is a tree hierarchical view of processes’ relationships. To see the tree, do htop in command line.


We’ve stated earlier that a process will be assigned a unique pid. That is not wrong but it is true conditionally. Only active processes get their own unique PIDs. the PID of a process will be recycled by the operating system when the process dies.


ChildStates The operating system sets the child’s status when the child exits. The minimum job its parent has to do is read its exit status.

There are two cases for unfinished cleanup of resources of kids.

The regular routine is as follows:

  • The process dies before its parent does.
  • Parent reads its exit status status when it dies.

A zombie process is a process whose exit status has not yet been acknowledged by its parent. A process is called an orphan process if its parent dies before it does. Note that a zombie process maintains its state as long as its exit code is not read, regardless of its parent state (i.e. the parent could be dead).