GitHub icon

Operating System Series - Process (Part I)

This blog post is going to be the first one in my OS series. Without any second thought, I decided to write on the topic process, as it's the fundamental concept around which the other elements of OS is built.

Without any further introduction, let's dive in.

What is a Process?

First, let me provide an academic definition of Process followed by practical illustrations. Process is a running instance of a program/code. Several processes can run the same program, but each Process has its own state. Example: You can open multiple instances of some applications like Firefox, Microsoft Word, etc. Each one maintains its process state. A process executes the instructions sequentially (one at a time).

Let's see how the execution of a program looks in the memory. Let's take the following program an example.

void foo(int f) {
	cout<<"I'm foo and my value is "<< f; 
}

int main() {
	foo(5); 
	return 0;
}
foo.cpp

In the context of the Process, the above program will look like the following diagram.

Program in the context of process

Note: The text segment will have assembly code or executable code. Just for the sake of illustration, I've used the high-level code.

As shown in the diagram, the program has to be organized in the following segments for the execution.

Data segment

The data segment generally holds the global variables and the static variables of the program.

Heap segment

The dynamic allocation of memory is achieved by reserving a desired space in the heap memory. Example: In C++, when we do new() / malloc(), the Process reserves the requested size from the heap segment. And, when we deallocate the memory by free(), the reserved space is given back to the heap memory marking it as free memory.

Stack segment

The stack segment holds the local variables, function parameters of each function. You can think of it as any state that needs to be maintained to execute a function, will be placed in that function's stack segment.

Text segment

The text segment holds the program or code in an executable format like in Assembly code. As it was already pointed out that a process executes the program sequentially, we have a pointer called Program Counter (PC) that points what's the next instruction to be executed.

Process Execution State

Every Process has a state attached to it, indicating what it is doing. There are five states in the process lifecycle. Each state is listed below.

  • New: OS creates a new process
  • Running: executing instructions on the CPU
  • Ready: ready to run, but waiting for the CPU
  • Waiting: waiting for an event to complete (most I/O operation(s) of the Process).
  • Terminated: OS destroys the Process.

As the program executes, it moves from state to state as a result of the program executions (e.g., system call), OS actions (scheduling), and external actions (interrupts).

Process lifecycle

When a process moves from running state to waiting state, OS will give the CPU time to another process in the ready state in the meantime. The Process moves to the waiting state when the OS schedules another process to execute on CPU. Also, the Process will go to the waiting state when it waits for the system call it made to complete.

Process state sequence with an example

The data structure of a Process

The data structure used to maintain execution state, program counter, stack pointer, etc. is Process Control Block (PCB). OS allocates a new PCB on the creation of each Process and places it on a state queue. The OS deallocates the PCB when the Process terminates. The PCB holds the following for the execution of the Process.

  • Process State (running, waiting, etc.)
  • Process ID (pid)
  • Program Counter (PC)
  • Stack pointer
  • Register values
  • Memory management info
  • List of open files
  • Queue pointers for state queues
  • Scheduling info (e.g., priority)
  • I/O status

Activity Monitor/Task Manager applications read the PCB table and show the process information to the users.

Process State Queues

OS maintains the PCBs of all the processes in state queues. It places the PCBs of all the processes in the same execution state in the appropriate state queue. When the OS changes the state of a process, the PCB is unlinked from its current state queue and moved to its new state queue. Each I/O device has its own wait queue. Example: If a group of processes is waiting for data to be fetched from a disk block, all those processes will be put in the disk waiting queue.

State Queues

The PCBs of the same state queue are linked together using a doubly-linked list.

e.g. State queues with PCBs linked

Note: The size of the running queue will be equal to the number of CPU cores. The size of the other queues is unbounded.

This marks the end of Process Part-I. In Part-II, we will further discuss the process context switch, parent, and child process.

Thanks for reading :)

Reference: