Introduction to Operating Systems

[!NOTE] This module explores the core principles of Introduction to Operating Systems, deriving solutions from first principles and hardware constraints to build world-class, production-ready expertise.

1. The Invisible Manager

An Operating System (OS) is the most complex piece of software running on your computer, yet its goal is to be invisible. It sits between the Hardware (Metal) and the User (Applications).

If you didn’t have an OS, every program you write would need to:

  1. Know exactly how to spin the hard drive motor.
  2. Manually send voltage to the pixels on the screen.
  3. Listen for electrical signals from the keyboard.

The OS solves two fundamental problems:

  1. Abstraction (The API): Turning ugly hardware into beautiful logical objects (Files, Sockets, Processes).
  2. Arbitration (The Manager): Deciding who gets to use the CPU and RAM when everyone wants it at once.

2. Role 1: Abstraction (The API)

Hardware is messy. It speaks in interrupts, registers, and memory addresses. The OS hides this mess behind a clean Application Programming Interface (API) called System Calls.

Reality (Hardware) Illusion (OS Abstraction)
Sectors, Tracks, Heads, Cylinders File (report.pdf)
Network Card, Voltage, Ethernet Frame Socket (TCP Connection)
CPU Cores, Registers, Cache Lines Process / Thread
Physical RAM Addresses Virtual Memory

Code Example: Creating a Process

Instead of manually initializing the CPU instruction pointer, we ask the OS to “Run this program”.

import java.io.IOException;

public class ProcessCreator {
    public static void main(String[] args) {
        // The OS Abstraction: "ProcessBuilder"
        // We don't need to know how to allocate CPU registers.
        ProcessBuilder pb = new ProcessBuilder("ls", "-l");

        try {
            Process process = pb.start(); // Makes a clone() syscall
            System.out.println("Started process PID: " + process.pid());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
package main

import (
    "fmt"
    "os/exec"
)

func main() {
    // The OS Abstraction: "exec.Command"
    // Wraps the fork/exec syscalls
    cmd := exec.Command("ls", "-l")

    if err := cmd.Start(); err != nil {
        panic(err)
    }

    fmt.Printf("Started process PID: %d\n", cmd.Process.Pid)
}

3. Role 2: Arbitration (The Manager)

Resources are finite.

  • CPU: You have 8 cores. You have 200 processes (Chrome, Spotify, VS Code). Who runs next?
  • RAM: You have 16GB. Chrome wants 12GB. Docker wants 8GB. Who crashes?

The OS is the Resource Arbiter. It uses policies (Scheduling, Paging) to share resources fairly (or unfairly).

Interactive: The Resource Arbiter

You are the OS Scheduler. Processes are queueing up. You have 1 CPU. Goal: Keep the CPU busy but don’t let the queue overflow.

CPU CORE 0

IDLE
Ready Queue (FIFO)
Waiting for processes...

[!TIP] War Story: The OOM Killer The Problem: During a massive Black Friday event at an e-commerce company, the central cache server began leaking memory. The 128GB of RAM filled completely.

The Arbiter Steps In: When memory reaches 100%, the OS faces a catastrophic failure. If it can’t allocate RAM, the entire machine will crash. The Linux Kernel has a draconian but necessary arbitration policy called the Out-Of-Memory (OOM) Killer. It calculates a “badness” score for every process, and ruthlessly kills the process consuming the most memory to save the system. In this case, the OS terminated the cache server database process, instantly bringing down the entire site. The OS acted to save itself, highlighting the harsh realities of resource limits and why understanding the kernel’s arbitration policies is critical for reliable system design.


4. Summary

The OS is a dual-natured beast:

  1. For the Programmer: It is a library of helper functions (System Calls).
  2. For the System: It is a dictator that manages scarce resources (CPU/RAM).

Next, we look at the Kernel, the core component that enforces these rules.