Topic Overview

PCB (Process Control Block)

Learn Process Control Block structure that stores process state and context information for process management and context switching.

Process Control Block (PCB) is a data structure that stores all information about a process needed by the operating system for process management, scheduling, and context switching.


What is a PCB?

PCB (Process Control Block) contains:

  • Process identification: Process ID (PID), parent PID
  • CPU state: Registers, program counter, stack pointer
  • Memory information: Page table, memory limits
  • I/O status: Open files, devices
  • Scheduling information: Priority, state, CPU time
  • Accounting: Start time, CPU time used

Purpose:

  • Context switching: Save/restore process state
  • Process management: Track process information
  • Scheduling: Determine which process to run
  • Resource management: Track resources used

PCB Structure

Typical PCB Fields

PCB Structure:
  - Process ID (PID)
  - Parent Process ID (PPID)
  - Process State (Ready, Running, Blocked, etc.)
  - Program Counter (PC)
  - CPU Registers (AX, BX, CX, DX, SP, etc.)
  - Memory Management Info
    - Page table pointer
    - Memory limits
    - Base and limit registers
  - I/O Status
    - Open files
    - I/O devices
  - Scheduling Information
    - Priority
    - CPU time used
    - Time quantum remaining
  - Accounting Information
    - Start time
    - CPU time
    - Memory used

PCB and Process States

Process states stored in PCB:

  • NEW: Process being created
  • READY: Process ready to run, waiting for CPU
  • RUNNING: Process currently executing
  • BLOCKED: Process waiting for I/O or event
  • TERMINATED: Process finished

State transitions:

NEW → READY → RUNNING → READY (time slice expired)
RUNNING → BLOCKED (I/O wait)
BLOCKED → READY (I/O complete)
RUNNING → TERMINATED (process ends)

PCB and Context Switching

Context switching uses PCB:

1. Save current process state to PCB
   - Save CPU registers
   - Save program counter
   - Save memory management info

2. Load next process state from PCB
   - Load CPU registers
   - Load program counter
   - Load memory management info

Examples

PCB Implementation

// PCB structure in C
typedef struct {
    // Process identification
    int pid;
    int ppid;  // Parent process ID
    
    // Process state
    enum {
        NEW,
        READY,
        RUNNING,
        BLOCKED,
        TERMINATED
    } state;
    
    // CPU state
    int program_counter;
    int stack_pointer;
    int registers[16];  // CPU registers
    
    // Memory management
    void* page_table;
    int memory_base;
    int memory_limit;
    
    // I/O status
    FILE* open_files[10];
    int io_devices[5];
    
    // Scheduling
    int priority;
    int cpu_time_used;
    int time_quantum;
    
    // Accounting
    time_t start_time;
    int cpu_time;
    int memory_used;
} PCB;

PCB Operations

class ProcessControlBlock:
    def __init__(self, pid):
        # Process identification
        self.pid = pid
        self.ppid = None
        
        # Process state
        self.state = 'NEW'
        
        # CPU state
        self.program_counter = 0
        self.stack_pointer = 0
        self.registers = {
            'AX': 0, 'BX': 0, 'CX': 0, 'DX': 0,
            'SP': 0, 'BP': 0, 'SI': 0, 'DI': 0
        }
        
        # Memory management
        self.page_table = None
        self.memory_base = 0
        self.memory_limit = 0
        
        # I/O status
        self.open_files = []
        self.io_devices = []
        
        # Scheduling
        self.priority = 0
        self.cpu_time_used = 0
        self.time_quantum = 10  # milliseconds
        
        # Accounting
        self.start_time = time.time()
        self.cpu_time = 0
        self.memory_used = 0
    
    def save_cpu_state(self, cpu_state):
        """Save CPU state to PCB"""
        self.program_counter = cpu_state['PC']
        self.stack_pointer = cpu_state['SP']
        self.registers = cpu_state['registers'].copy()
    
    def restore_cpu_state(self):
        """Restore CPU state from PCB"""
        return {
            'PC': self.program_counter,
            'SP': self.stack_pointer,
            'registers': self.registers.copy()
        }
    
    def update_state(self, new_state):
        """Update process state"""
        self.state = new_state
    
    def get_info(self):
        """Get process information"""
        return {
            'pid': self.pid,
            'state': self.state,
            'cpu_time': self.cpu_time,
            'memory_used': self.memory_used
        }

Common Pitfalls

  • Not saving all state: Missing registers causes corruption. Fix: Save all CPU state
  • PCB corruption: PCB overwritten. Fix: Protect PCB, use proper locking
  • Memory leaks: PCBs not freed. Fix: Free PCB when process terminates
  • State inconsistency: PCB state doesn't match process. Fix: Update PCB on state changes

Interview Questions

Beginner

Q: What is a PCB and what information does it store?

A:

PCB (Process Control Block) is a data structure storing all information about a process.

Information stored:

  • Process identification: PID, parent PID
  • CPU state: Registers, program counter, stack pointer
  • Memory information: Page table, memory limits
  • I/O status: Open files, devices
  • Scheduling: Priority, state, CPU time
  • Accounting: Start time, CPU time used

Purpose:

  • Context switching: Save/restore process state
  • Process management: Track process information
  • Scheduling: Determine which process to run

Example:

PCB for Process 123:
  PID: 123
  State: RUNNING
  PC: 0x1234
  Registers: [AX=10, BX=20, ...]
  Memory: Page table at 0x5000
  Priority: 5

Intermediate

Q: Explain how PCB is used in context switching and process scheduling.

A:

Context Switching:

  1. Save current process state

    # Save CPU state to PCB
    current_process.pcb.save_cpu_state(cpu_state)
    current_process.pcb.state = 'READY'
    
  2. Select next process

    next_process = scheduler.select_next()
    
  3. Restore next process state

    # Load CPU state from PCB
    cpu_state = next_process.pcb.restore_cpu_state()
    next_process.pcb.state = 'RUNNING'
    

Process Scheduling:

Scheduler uses PCB information:

  • State: Only schedule READY processes
  • Priority: Higher priority processes first
  • CPU time: Track time used for scheduling decisions
  • I/O status: Blocked processes not scheduled

Example:

def schedule():
    ready_processes = [p for p in processes if p.pcb.state == 'READY']
    
    # Sort by priority
    ready_processes.sort(key=lambda p: p.pcb.priority, reverse=True)
    
    # Select highest priority
    next_process = ready_processes[0]
    
    # Context switch
    switch_context(current_process, next_process)

PCB fields used:

  • State: Determine if process can run
  • Priority: Scheduling decision
  • CPU time: Time slice management
  • Registers: Context switching

Senior

Q: Design a PCB management system for an OS that handles millions of processes. How do you optimize PCB storage, context switching, and process lookup?

A:

class PCBManagementSystem {
  private pcbs: Map<number, PCB>;
  private pcbPool: PCBPool;
  private index: ProcessIndex;
  
  constructor() {
    this.pcbs = new Map();
    this.pcbPool = new PCBPool();
    this.index = new ProcessIndex();
  }
  
  // 1. PCB Allocation
  class PCBPool {
    private pool: PCB[];
    
    allocate(pid: number): PCB {
      // Reuse from pool or create new
      let pcb = this.pool.pop();
      if (!pcb) {
        pcb = new PCB(pid);
      } else {
        pcb.reset(pid);
      }
      return pcb;
    }
    
    deallocate(pcb: PCB): void {
      // Return to pool
      pcb.cleanup();
      this.pool.push(pcb);
    }
  }
  
  // 2. Optimized PCB Structure
  class PCB {
    // Compact structure for memory efficiency
    private compact: CompactPCB;
    private extended: ExtendedPCB; // Only when needed
    
    saveCPUState(cpuState: CPUState): void {
      // Save only modified registers (lazy saving)
      this.compact.modifiedRegisters = this.getModified(cpuState);
      this.compact.programCounter = cpuState.PC;
    }
  }
  
  // 3. Fast Process Lookup
  class ProcessIndex {
    private byPid: Map<number, PCB>;
    private byState: Map<string, Set<number>>;
    private byPriority: PriorityQueue;
    
    getByPid(pid: number): PCB {
      return this.byPid.get(pid);
    }
    
    getReadyProcesses(): PCB[] {
      const pids = this.byState.get('READY');
      return Array.from(pids).map(pid => this.byPid.get(pid));
    }
    
    getHighestPriority(): PCB {
      return this.byPriority.peek();
    }
  }
  
  // 4. Context Switching Optimization
  optimizeContextSwitch(): void {
    // Lazy register saving: Only save modified registers
    // Use CPU hardware support for fast context switch
    // Cache frequently accessed PCBs
  }
  
  // 5. Memory Optimization
  optimizeMemory(): void {
    // Compact PCB structure
    // Extended info only when needed
    // Pool PCBs for reuse
  }
}

Features:

  1. PCB pool: Reuse PCBs to reduce allocation overhead
  2. Compact structure: Minimize memory usage
  3. Fast lookup: Index by PID, state, priority
  4. Lazy saving: Only save modified registers
  5. Memory efficient: Compact structure, extended when needed

Key Takeaways

  • PCB: Data structure storing all process information
  • Contents: PID, CPU state, memory info, I/O status, scheduling info
  • Context switching: Save/restore process state using PCB
  • Process scheduling: Scheduler uses PCB information (state, priority)
  • Process states: NEW, READY, RUNNING, BLOCKED, TERMINATED
  • Memory management: PCB stores page table, memory limits
  • Best practices: Save all state, protect PCB, free when process terminates

About the author

InterviewCrafted helps you master system design with patience. We believe in curiosity-led engineering, reflective writing, and designing systems that make future changes feel calm.