A university-level introduction to Operating Systems — from what an OS actually does, to how processes are scheduled, memory is managed, and files are stored o…
If you've ever wondered what's really happening between you clicking an icon and a program appearing on your screen, this course is for you. We'll build up your understanding piece by piece, using plain-language explanations, real-world analogies, comparison tables, and pseudocode — no prior systems knowledge assumed.
Table of Contents
- Introduction & History
- Operating System Structures
- Process Management
- CPU Scheduling
- Process Synchronization
- Deadlocks
- Memory Management
- Virtual Memory
- File Systems
- I/O Systems
- Security & Protection
- Case Studies: Linux, Windows & Mobile OSes
- Further Reading
- Final Review Quiz
1. Introduction & History
1.1 What Is an Operating System?
An Operating System (OS) is the software layer that sits between your computer's hardware and the applications you run. It is often described as a resource manager and an abstraction provider:
- Resource manager — it decides which program gets the CPU, how much memory each program can use, and in what order data is written to disk.
- Abstraction provider — it hides the messy details of hardware (registers, disk sectors, network packets) behind clean, simple interfaces (files, windows, sockets) that application developers can use without needing to know how the hardware works.
Think of the OS as an air traffic controller at a busy airport. Planes (programs) all want to take off, land, and use limited runways (CPU, memory, disk) at the same time. The controller's job isn't to fly the planes — it's to make sure they don't collide and that resources are shared fairly and safely.
1.2 Core Goals of an OS
| Goal |
Description |
| Convenience |
Make the computer easier to use via simple interfaces (GUI, shell, APIs) |
| Efficiency |
Use hardware resources (CPU, memory, I/O devices) optimally |
| Ability to evolve |
Allow new features and hardware to be added without redesigning everything |
| Protection & Security |
Prevent programs and users from interfering with each other |
| Fairness |
Ensure resources are shared reasonably among competing processes |
1.3 A Brief History of Operating Systems
| Era |
Approach |
Key Idea |
| 1940s–50s |
No OS |
Programmers ran one program at a time by manually operating the machine |
| Late 1950s |
Batch systems |
Jobs were grouped ("batched") and run sequentially without user interaction |
| 1960s |
Multiprogramming |
Multiple jobs kept in memory at once; CPU switches to another job when one is waiting on I/O, keeping the CPU busy |
| 1960s–70s |
Time-sharing systems |
The CPU rapidly switches between users' jobs, giving each the illusion of having the machine to themselves (e.g. early UNIX) |
| 1980s |
Personal computer OSes |
Single-user, single-machine systems (MS-DOS, early Mac OS) |
| 1990s–2000s |
Distributed & networked OSes |
Systems designed to coordinate resources across multiple connected machines |
| 2000s–present |
Real-time & mobile OSes |
Systems with strict timing guarantees (embedded, industrial) and OSes built for phones/tablets (Android, iOS) with power and touch-interface constraints |
Key takeaway: Each era solved a specific bottleneck — batch systems solved "programmers wasting expensive machine time," multiprogramming solved "the CPU sitting idle during I/O," and time-sharing solved "users wanting interactive access." Every concept in this course descends from one of these problems.
⬆ Back to Table of Contents
2. Operating System Structures
2.1 The Kernel
The kernel is the core part of the OS that runs with the highest privilege level and has direct access to hardware. Everything else (utilities, GUI, applications) runs on top of it.
2.2 Kernel Architectures
| Architecture |
Description |
Pros |
Cons |
Examples |
| Monolithic |
Entire OS (process management, memory management, file systems, drivers) runs as one large program in kernel space |
Fast (no message-passing overhead) |
A bug in any component can crash the whole system |
Linux, traditional UNIX |
| Microkernel |
Only the bare essentials (IPC, basic scheduling, basic memory management) run in kernel space; everything else runs as separate user-space processes |
More stable and secure — a crashing driver doesn't crash the OS |
Slower due to message-passing between components |
QNX, MINIX, seL4 |
| Hybrid |
Combines monolithic performance with some microkernel-style modularity |
Balances speed and stability |
More complex to design |
Windows NT-based systems, macOS (XNU) |
2.3 System Calls
A system call is the mechanism by which a user program requests a service from the kernel — for example, reading a file, creating a process, or sending network data. Since applications run in user mode (restricted) and the kernel runs in kernel mode (privileged), a system call triggers a controlled switch between the two.
Common categories of system calls:
- Process control —
fork(), exec(), exit()
- File management —
open(), read(), write(), close()
- Device management —
ioctl(), read(), write()
- Information maintenance —
getpid(), alarm()
- Communication —
pipe(), socket(), send(), recv()
2.4 The Boot Process
- Power-on self-test (POST) — firmware checks hardware is functional
- Bootloader loads — a small program (e.g. GRUB, Windows Boot Manager) locates and loads the OS kernel into memory
- Kernel initialization — the kernel sets up core data structures, device drivers, and memory management
- Init process starts — the first user-space process (
init, systemd, or similar) launches, which in turn starts system services and eventually a login prompt or desktop environment
⬆ Back to Table of Contents
3. Process Management
3.1 What Is a Process?
A process is a program in execution — it includes the program's code, its current activity (represented by the value of the program counter), a stack, a data section, and a heap.
Process vs. Program: A program is a passive entity (e.g., a file sitting on disk). A process is an active entity — the program plus its execution state.
3.2 Process vs. Thread
|
Process |
Thread |
| Definition |
An independent program in execution with its own memory space |
A lightweight unit of execution within a process, sharing that process's memory |
| Memory |
Has its own separate address space |
Shares the address space of its parent process |
| Communication |
Requires Inter-Process Communication (IPC) — slower |
Can communicate directly via shared memory — faster |
| Creation cost |
Expensive (new memory space, resources) |
Cheap (reuses parent's resources) |
| Crash impact |
Crash of one process doesn't directly affect others |
A crash in one thread can bring down the whole process |
3.3 Process States
A process moves through a well-defined lifecycle:
admitted scheduler dispatch
NEW ─────────────► READY ─────────────────► RUNNING
▲ │
│ interrupt │
└──────────────────────────┘
│
I/O or event wait│ event/I/O
▼ completes
WAITING ◄────────┘
RUNNING ───► TERMINATED (exit)
- New — the process is being created
- Ready — the process is waiting to be assigned to a CPU
- Running — instructions are being executed
- Waiting — the process is waiting for some event (e.g. I/O completion)
- Terminated — the process has finished execution
3.4 The Process Control Block (PCB)
Every process is represented in the OS by a Process Control Block, a data structure that stores:
- Process ID (PID)
- Process state
- Program counter
- CPU registers
- CPU scheduling information (priority, etc.)
- Memory management information (page tables, segment tables)
- Accounting information (CPU used, time limits)
- I/O status information (open files, allocated devices)
3.5 Context Switching
A context switch occurs when the CPU switches from executing one process to another. The OS saves the state (PCB) of the currently running process and loads the saved state of the next process to run. Context switches are pure overhead — no useful work is done during the switch itself — so an efficient OS minimizes how often they're needed relative to actual work performed.
3.6 Inter-Process Communication (IPC)
Since processes have separate memory spaces, they need explicit mechanisms to communicate:
| Mechanism |
How it works |
| Pipes |
A unidirectional (or, with two pipes, bidirectional) communication channel, typically between related processes |
| Message Queues |
Processes send and receive discrete messages via a kernel-managed queue |
| Shared Memory |
A region of memory mapped into multiple processes' address spaces — fastest IPC method, but requires manual synchronization |
| Sockets |
Communication endpoints that work across processes on the same machine or over a network |
| Signals |
Software interrupts sent to a process to notify it of an event (e.g. SIGKILL, SIGTERM) |
⬆ Back to Table of Contents
4. CPU Scheduling
4.1 Why Scheduling Matters
With multiple processes competing for a limited number of CPUs, the OS needs a scheduler to decide which process runs next. Good scheduling improves CPU utilization, throughput, and responsiveness.
4.2 Scheduling Criteria
| Criterion |
Goal |
| CPU Utilization |
Keep the CPU as busy as possible |
| Throughput |
Maximize the number of processes completed per unit time |
| Turnaround Time |
Minimize total time from submission to completion |
| Waiting Time |
Minimize time a process spends in the ready queue |
| Response Time |
Minimize time from request submission to first response (critical for interactive systems) |
4.3 Scheduling Algorithms
| Algorithm |
How It Works |
Preemptive? |
Pros |
Cons |
| First-Come, First-Served (FCFS) |
Processes run in the order they arrive |
No |
Simple to implement |
"Convoy effect" — short jobs stuck behind long ones |
| Shortest Job First (SJF) |
The process with the smallest estimated run time goes next |
Can be either |
Optimal average waiting time |
Requires knowing job length in advance; can starve long jobs |
| Round Robin (RR) |
Each process gets a small fixed time slice ("quantum"); if not finished, it goes to the back of the queue |
Yes |
Fair, good for time-sharing systems |
Performance heavily depends on quantum size |
| Priority Scheduling |
Each process is assigned a priority; highest priority runs first |
Can be either |
Important tasks run sooner |
Low-priority processes can starve (solved via "aging") |
| Multilevel Queue |
Processes are split into separate queues by type (e.g. foreground/interactive vs. background/batch), each with its own scheduling algorithm |
Yes |
Tailors scheduling to process type |
Rigid; a process can't move between queues |
| Multilevel Feedback Queue |
Like multilevel queue, but processes can move between queues based on behavior (e.g. CPU-bound processes get demoted) |
Yes |
Highly flexible, adapts to process behavior |
Complex to configure |
4.4 Worked Example: Round Robin
Given three processes with the following burst times, and a time quantum of 4ms:
| Process |
Burst Time |
| P1 |
10ms |
| P2 |
5ms |
| P3 |
8ms |
Execution order: P1(4) → P2(4) → P3(4) → P1(4) → P2(1) → P3(4) → P1(2)
Each process gets a fair share of the CPU in rotation, rather than one process monopolizing it — this is why Round Robin is the backbone of most interactive time-sharing systems.
4.5 Multiprocessor Scheduling
On systems with multiple CPU cores, additional questions arise:
- Asymmetric multiprocessing — one core makes all scheduling decisions for all cores
- Symmetric multiprocessing (SMP) — each core manages its own scheduling, usually from a shared ready queue
- Processor affinity — the tendency to keep a process running on the same core it ran on before, to take advantage of "warm" cache data
- Load balancing — redistributing processes across cores to avoid one core being overloaded while another sits idle
⬆ Back to Table of Contents
5. Process Synchronization
5.1 The Race Condition Problem
A race condition occurs when multiple processes or threads access and modify shared data concurrently, and the final result depends on the unpredictable timing of their execution.
Example: Two threads both execute counter = counter + 1. If both read counter before either writes back, one increment gets lost.
5.2 The Critical Section Problem
The critical section is the part of a program where shared resources are accessed. A correct solution must satisfy three conditions:
- Mutual Exclusion — only one process may execute in its critical section at a time
- Progress — if no process is in its critical section, one of the processes waiting to enter must be allowed in without indefinite delay
- Bounded Waiting — there must be a limit on how many times other processes can enter their critical section before a waiting process gets its turn
5.3 Synchronization Tools
| Tool |
Description |
| Mutex (Mutual Exclusion Lock) |
A simple lock: a thread must acquire it before entering a critical section and release it after. Only one thread can hold it at a time |
| Semaphore |
An integer variable accessed only through two atomic operations, wait() (decrement) and signal() (increment). A binary semaphore (0 or 1) behaves like a mutex; a counting semaphore can manage a pool of multiple identical resources |
| Monitor |
A high-level synchronization construct that bundles shared data with the procedures that operate on it, automatically enforcing mutual exclusion |
Semaphore pseudocode:
wait(S):
while S <= 0:
// busy-wait or block
S = S - 1
signal(S):
S = S + 1
5.4 Classic Synchronization Problems
| Problem |
Scenario |
Key Challenge |
| Producer-Consumer |
A producer generates data into a shared buffer; a consumer removes it |
Preventing the producer from overfilling the buffer and the consumer from reading an empty one |
| Readers-Writers |
Multiple readers can access shared data simultaneously, but writers need exclusive access |
Balancing reader concurrency against writer starvation |
| Dining Philosophers |
Five philosophers sit at a table with one fork between each pair; each needs both forks to eat |
Avoiding deadlock (everyone picks up their left fork and waits forever for their right) |
⬆ Back to Table of Contents
6. Deadlocks
6.1 What Is a Deadlock?
A deadlock occurs when a set of processes are each waiting for a resource held by another process in the same set, so none of them can ever proceed.
6.2 The Four Necessary Conditions
A deadlock can only occur if all four of these conditions hold simultaneously:
- Mutual Exclusion — at least one resource must be held in a non-shareable mode
- Hold and Wait — a process holding at least one resource is waiting to acquire additional resources held by others
- No Preemption — resources cannot be forcibly taken away; they must be released voluntarily
- Circular Wait — a closed chain of processes exists, each waiting for a resource held by the next
6.3 Handling Deadlocks
| Strategy |
Approach |
| Prevention |
Design the system so at least one of the four necessary conditions can never hold |
| Avoidance |
Grant resource requests only if the resulting system state is "safe" (e.g. the Banker's Algorithm) |
| Detection & Recovery |
Allow deadlocks to occur, detect them (via resource-allocation graphs), then recover by terminating or preempting processes |
| Ignorance ("Ostrich Algorithm") |
Assume deadlocks are rare enough not to be worth handling — used by many general-purpose OSes including most UNIX variants |
6.4 The Banker's Algorithm (Simplified)
The Banker's Algorithm avoids deadlock by only granting a resource request if, after granting it, the system remains in a safe state — meaning there still exists some order in which all processes could finish.
function isSafe(available, maxNeed, allocated):
work = available
finish = [false] * numberOfProcesses
while there exists a process P where:
finish[P] == false AND
(maxNeed[P] - allocated[P]) <= work:
work = work + allocated[P]
finish[P] = true
return all(finish) == true
If granting a request would lead to an unsafe state, the OS makes the requesting process wait, even though the resources may technically be available.
⬆ Back to Table of Contents
7. Memory Management
7.1 Address Binding
Before a program can run, its logical (relative) addresses must be mapped to physical memory addresses. This binding can happen:
- Compile time — if the memory location is known in advance
- Load time — if the location isn't known until the program is loaded
- Execution time — if the process can be moved during execution (most modern systems use this, via hardware support)
7.2 Contiguous Memory Allocation
Early systems allocated each process a single contiguous block of memory.
- Fixed partitioning — memory is divided into fixed-size blocks; simple but wastes space (internal fragmentation) when a process is smaller than its partition
- Dynamic partitioning — partitions are created to exactly fit each process, but over time this leaves scattered small gaps too small to be useful (external fragmentation)
Allocation strategies for dynamic partitioning:
| Strategy |
Description |
| First Fit |
Allocate the first hole big enough |
| Best Fit |
Allocate the smallest hole big enough (minimizes leftover space, but is slower and creates many tiny unusable holes) |
| Worst Fit |
Allocate the largest available hole (leaves the biggest usable leftover chunk) |
7.3 Paging
Paging solves fragmentation by dividing physical memory into fixed-size blocks called frames, and logical memory into blocks of the same size called pages. A process's pages can be scattered across non-contiguous frames, and a page table tracks the mapping from each page to its frame.
Because there is no requirement for a process to occupy contiguous memory, external fragmentation disappears (though a small amount of internal fragmentation can remain in the last page).
7.4 Segmentation
Segmentation divides a program into logical units that make sense to the programmer — e.g. code segment, data segment, stack segment — each of variable size. This maps more naturally to how programs are structured, though it can reintroduce external fragmentation. Many modern systems use a hybrid of segmentation with paging, gaining the logical structure of segments and the fragmentation-free allocation of paging.
⬆ Back to Table of Contents
8. Virtual Memory
8.1 Why Virtual Memory?
Virtual memory lets a process run without its entire address space being loaded into physical RAM at once. This allows programs larger than physical memory to run, and lets more processes fit in memory simultaneously, improving CPU utilization.
8.2 Demand Paging
Under demand paging, a page is only loaded into physical memory when it's actually referenced. If a process accesses a page not currently in memory, a page fault occurs, and the OS:
- Checks if the reference is valid
- Finds a free frame (or selects a victim page to evict)
- Loads the required page from disk into that frame
- Updates the page table
- Resumes the instruction that caused the fault
8.3 Page Replacement Algorithms
When memory is full and a new page must be loaded, the OS must choose an existing page to evict:
| Algorithm |
Strategy |
Notes |
| FIFO (First-In, First-Out) |
Evict the page that has been in memory the longest |
Simple but can suffer from Belady's Anomaly (more frames can sometimes cause more faults) |
| Optimal (OPT) |
Evict the page that won't be used for the longest time in the future |
Best possible performance, but requires knowing the future — used only as a theoretical benchmark |
| LRU (Least Recently Used) |
Evict the page that hasn't been used for the longest time in the past |
Good approximation of OPT; more expensive to implement in hardware/software |
| Clock (Second-Chance) |
An efficient approximation of LRU using a circular list and a reference bit |
Common in real-world systems as a practical LRU substitute |
8.4 Thrashing
Thrashing occurs when a process doesn't have enough frames to hold its actively used pages (its working set), so it spends more time faulting pages in and out than doing actual work — CPU utilization can drop sharply even though the system looks "busy."
8.5 The Working Set Model
The working set of a process is the set of pages it has referenced in the most recent time window (Δ). The OS tries to keep each process's working set resident in memory; if the combined working sets of all active processes exceed available memory, the system reduces the degree of multiprogramming (fewer processes run concurrently) to prevent thrashing.
⬆ Back to Table of Contents
9. File Systems
9.1 What Is a File?
A file is a named collection of related information, typically persistent, stored on secondary storage (disk, SSD). Files have attributes (name, size, type, permissions, timestamps) and support operations like create, read, write, delete, and append.
9.2 Directory Structures
| Structure |
Description |
| Single-Level Directory |
All files exist in one flat directory — simple but causes naming conflicts |
| Two-Level Directory |
Each user has their own directory, avoiding conflicts between users |
| Tree-Structured Directory |
Directories can contain subdirectories, forming a hierarchy (the model used by virtually all modern OSes) |
| Acyclic Graph Directory |
Allows files/directories to be shared via links (e.g. shortcuts, hard links) while still forming a directed acyclic structure |
9.3 File Allocation Methods
| Method |
How It Works |
Pros |
Cons |
| Contiguous Allocation |
Each file occupies a set of contiguous blocks on disk |
Fast sequential and direct access |
Suffers external fragmentation; hard to grow files |
| Linked Allocation |
Each file is a linked list of blocks scattered across disk |
No external fragmentation; files can grow easily |
Slow direct access; pointer overhead; risk of corruption if a link breaks |
| Indexed Allocation |
An index block stores pointers to all of a file's blocks |
Supports fast direct access without external fragmentation |
Index block itself uses overhead; needs strategy for very large files (e.g. multi-level indexing) |
9.4 Free Space Management
The OS must track which disk blocks are free:
- Bit Vector — one bit per block (1 = free, 0 = allocated); simple and compact
- Linked List — free blocks are chained together in a list
- Grouping — the first free block stores addresses of several other free blocks
- Counting — since blocks are often allocated/freed in contiguous chunks, store the starting address and count of free blocks in a run
⬆ Back to Table of Contents
10. I/O Systems
10.1 I/O Hardware
Devices connect to the computer via controllers, which the OS communicates with through registers for data, status, and control. Two common data-transfer techniques:
- Polling — the CPU repeatedly checks a device's status register until it's ready; simple but wastes CPU cycles
- Interrupts — the device signals the CPU only when it needs attention, freeing the CPU to do other work in between
10.2 Direct Memory Access (DMA)
For high-volume data transfer (e.g. disk-to-memory), DMA allows a device to transfer data directly to/from memory without the CPU being involved in every byte, dramatically reducing CPU overhead.
10.3 Device Drivers
A device driver is a piece of software that provides a uniform interface for the OS to communicate with a specific hardware device, translating generic OS requests (like "read a block") into the device-specific commands the hardware understands.
10.4 Disk Scheduling Algorithms
Since the disk head must physically move to access data, the order in which requests are serviced matters a lot for performance:
| Algorithm |
Strategy |
| FCFS |
Service requests in the order they arrive |
| SSTF (Shortest Seek Time First) |
Service the request closest to the current head position next |
| SCAN ("Elevator Algorithm") |
The head moves in one direction, servicing requests, until it reaches the end, then reverses |
| C-SCAN (Circular SCAN) |
Like SCAN, but after reaching the end, the head jumps back to the beginning without servicing requests on the return trip, giving more uniform wait times |
⬆ Back to Table of Contents
11. Security & Protection
11.1 Protection vs. Security
- Protection — internal mechanisms that control access to resources within the system (e.g. file permissions)
- Security — defense against external and internal threats to the system as a whole (e.g. malware, unauthorized access)
11.2 Authentication
The process of verifying identity, typically via:
- Something you know (password, PIN)
- Something you have (security token, phone for 2FA)
- Something you are (biometrics — fingerprint, face)
11.3 Access Control
| Model |
Description |
| Access Control Lists (ACLs) |
Each resource has a list specifying which users/processes may access it and how |
| Capabilities |
Each process holds tokens ("capabilities") specifying what it's allowed to do, rather than the resource tracking who can access it |
| Role-Based Access Control (RBAC) |
Permissions are assigned to roles, and users are assigned to roles, simplifying management in large systems |
11.4 Common Threats
- Malware — viruses, worms, trojans, ransomware
- Privilege escalation — exploiting a vulnerability to gain higher-than-intended access
- Buffer overflow attacks — writing beyond allocated memory to overwrite adjacent memory, potentially executing malicious code
- Denial of Service (DoS) — overwhelming a system so legitimate users can't access it
⬆ Back to Table of Contents
12. Case Studies: Linux, Windows & Mobile OSes
| Feature |
Linux |
Windows |
Android (mobile) |
| Kernel type |
Monolithic (with loadable modules) |
Hybrid (Windows NT kernel) |
Modified Linux kernel |
| Process model |
fork() + exec() model; lightweight processes via clone() |
Uses a unified process/thread creation model (CreateProcess) |
Each app typically runs in its own process with its own Linux user ID for sandboxing |
| Scheduling |
Completely Fair Scheduler (CFS), based on virtual runtime |
Multilevel feedback queue with dynamic priorities |
Linux CFS, tuned for power efficiency and UI responsiveness |
| Memory management |
Demand paging, overcommit handling, OOM killer for extreme memory pressure |
Demand paging with a unified working-set-based memory manager |
Aggressive process termination under memory pressure (no traditional swap on most devices) |
| File system |
ext4, Btrfs, XFS among others |
NTFS |
A variant of ext4 or F2FS, often with encryption at the file level |
| Security model |
User/group permissions, SELinux/AppArmor for mandatory access control |
Discretionary access control, User Account Control (UAC), Windows Defender |
Per-app sandboxing, mandatory permission prompts, Play Protect scanning |
Takeaway: despite very different histories, all three systems solve the same core problems covered in this course — scheduling, memory management, protection — but tune their solutions differently based on their goals (server stability, desktop compatibility, or mobile battery/security constraints).
⬆ Back to Table of Contents
13. Further Reading
- Operating System Concepts — Silberschatz, Galvin, Gagne (the standard university textbook, often called "the Dinosaur Book")
- Modern Operating Systems — Andrew S. Tanenbaum
- Operating Systems: Three Easy Pieces — Remzi H. Arpaci-Dusseau & Andrea C. Arpaci-Dusseau (free online, excellent for self-study)
- The Linux kernel documentation at kernel.org
- The MIT 6.828/6.S081 "Operating System Engineering" course materials (freely available online)
⬆ Back to Table of Contents
14. Final Review Quiz
Test your understanding with these questions before moving on to advanced topics:
- What is the difference between a process and a thread, and why is thread creation cheaper?
- Name the four necessary conditions for a deadlock to occur.
- Why does Round Robin scheduling improve responsiveness compared to FCFS?
- What problem does paging solve that contiguous memory allocation doesn't?
- Explain thrashing and how the working set model helps prevent it.
- What are the three requirements a correct critical-section solution must satisfy?
- Compare FIFO and LRU page replacement — why does LRU generally perform better?
- What is the difference between protection and security in an OS context?
- Explain the purpose of DMA and why it reduces CPU overhead.
- Why do modern systems often combine segmentation with paging rather than using either alone?
Try answering these from memory before checking back against the relevant sections above — that's the fastest way to see what's actually sunk in.
#operatingsystems #computerscience #csfundamentals #techeducation #learntocode #softwareengineering #universitycourse #programming