CodeNFacts
CodeHub
Home

All Categories


Sign In
0x00Kernel-level knowledge

Operating Systems, from process to physical memory.

Every program you've ever run only worked because something quieter was managing the CPU, the memory, and the disk underneath it. This is that layer - explained, diagrammed, and boiled down to cheat sheets you can actually revise from.

0x00Foundations

What is an Operating System, really?

Strip away the desktop icons and it comes down to one job: turn one pile of shared hardware into something many programs can use safely, fairly, and at the same time.

// definition

Operating System (OS): system software that sits between hardware and applications, managing the CPU, memory, storage, and I/O devices, and exposing them to programs through a consistent set of services (system calls).

Think of the OS as a resource manager and a referee at the same time — it hands out CPU time slices, memory pages, and disk blocks, and it stops one program from trampling another's.

Why we use one

  • • Lets many programs share one CPU, one RAM, one disk — without each one needing to know about the others.
  • • Provides a stable, hardware-independent API (system calls) so software isn't rewritten per device.
  • • Enforces protection: one process's bug or malice can't (normally) corrupt another's memory.

Why we need one

  • • Hardware is dumb and single-minded — a CPU just executes instructions, it has no idea what "fair" means.
  • • Without an arbiter, two programs writing to the same memory address is a crash waiting to happen.
  • • Users need files, windows, and networking to *feel* simple — the OS absorbs the real complexity.

What if it disappeared?

Take the OS away and you're left with bare-metal hardware and no shared rules. Every application would need to hand-manage the CPU timeline itself, talk to disk controllers in raw hardware commands, and trust every other running program not to overwrite its memory. There'd be no multitasking, no file system abstraction, no plug-and-play devices — you'd be back to one program, one machine, one operator, like the earliest batch-processing computers of the 1950s.

0x01Where it shows up

Use cases

The same core ideas — scheduling, memory isolation, IPC — show up everywhere, just tuned differently.

Mobile

Android/iOS schedule apps, isolate them via processes/sandboxes, and manage battery-aware power states.

Servers & Cloud

Linux/Windows Server hosts thousands of containers and VMs, each relying on the kernel's scheduler and memory manager.

Embedded

Washing machines, routers, and car ECUs run tiny kernels (FreeRTOS, Zephyr) tuned for one job and a hard deadline.

IoT

Sensors run event-driven, low-power kernels that sleep almost always and wake only to sample and transmit.

Real-Time Control

Anti-lock brakes, pacemakers, and robotics need an RTOS that guarantees *when* a task finishes, not just that it does.

Virtualization

Hypervisors are OS-like layers that multiplex hardware across whole guest operating systems (VMware, KVM, Hyper-V).

0x02Architecture

Operating System structure

How the OS's own internals are organized changes how fast, safe, and maintainable it is.

Monolithic

Every service (drivers, FS, scheduler) runs in kernel space as one big program. Fast, but one bug can crash everything.

e.g. Linux, classic UNIX

Layered

The OS is split into numbered layers, each only using services of the layer below it.

e.g. Early THE OS

Microkernel

Kernel keeps only the bare minimum (IPC, scheduling, basic memory); drivers & file systems run in user space.

e.g. Minix, QNX, seL4

Hybrid

Monolithic core for speed, with microkernel-style modularity for select services.

e.g. Windows NT, macOS (XNU)

0x03The unit of work

Process management

A process is a program in execution — its code plus its own private stack, heap, data, and CPU register state.

// definition

Process Control Block (PCB): the kernel's record for a process — PID, program counter, CPU registers, scheduling info, memory limits, and open file list. It's what makes a context switch possible.

// definition

Context switch: saving the PCB of the running process and loading the PCB of the next one, so the CPU can jump between processes and still resume each exactly where it left off.

fig — Process state transitions

NewReadyRunningWaitingTerminatedadmitdispatchpreemptI/O waitI/O doneexit
0x04Who runs next

CPU scheduling

The scheduler decides which ready process gets the CPU next — the policy it uses trades off fairness, throughput, and responsiveness.

AlgorithmPreemptive?Starvation riskConvoy effectBest for
FCFSNoNoYesSimplicity, batch jobs
SJFNoYes (long jobs)NoMinimizing avg. waiting time
SRTFYesYesNoSJF + new-arrival responsiveness
PriorityEitherYesNoImportance-based ordering
Round RobinYesNoNoTime-sharing, fairness
MLFQYesPossibleNoMixed CPU/IO-bound workloads

Turnaround = Completion − Arrival. Waiting = Turnaround − Burst. Get comfortable with a Gantt chart by hand for FCFS/SJF/RR — almost every exam question reduces to this.

0x05Sharing safely

Process synchronization

When multiple processes/threads touch shared data, uncoordinated access causes race conditions — synchronization is how we stop that.

// definition

Critical section: the part of code where a process accesses shared resources. A valid solution needs mutual exclusion, progress, and bounded waiting.

// definition

Race condition: the outcome of concurrent execution depends on the exact timing/order of operations — usually a sign a critical section wasn't protected.

PrimitiveHow it worksTypical use
Mutex1 owner, binary lock/unlockProtect a single critical section
Semaphore (counting)Integer count, signal/waitBound access to N identical resources
Binary Semaphore0/1, any thread can signalSignaling between threads (not just mutual exclusion)
MonitorLanguage-level lock + condition varsHigh-level mutual exclusion (Java `synchronized`)
SpinlockBusy-waits instead of sleepingVery short critical sections on multicore

Classic synchronization problems

A bounded buffer shared by producers and consumers; needs empty/full counting semaphores + a mutex.
Many readers may read together; a writer needs exclusive access — variants favor readers, writers, or fairness.
5 philosophers, 5 forks; classic deadlock demo — fixed by resource ordering, a waiter, or limiting diners to 4.
Barber sleeps when idle; models bounded-waiting-room synchronization with limited seats.
0x06When everyone waits forever

Deadlocks

A deadlock is a set of processes each waiting for a resource held by another in the set — none of them can ever proceed.

fig — Resource Allocation Graph — a cycle means deadlock (single-instance resources)

P1P2R1R2requestholdsrequestholds

4 necessary conditions

1

Mutual Exclusion: At least one resource is held in a non-shareable mode.

2

Hold and Wait: A process holds one resource while waiting for another.

3

No Preemption: A resource can only be released voluntarily by the process holding it.

4

Circular Wait: A closed chain of processes, each waiting on a resource held by the next.

All four must hold simultaneously for a deadlock to be possible.

Handling strategies

StrategyApproach
PreventionDeny one of the 4 conditions structurally (e.g. request all resources at once).
AvoidanceGrant requests only if the system stays in a safe state — Banker's Algorithm.
Detection & RecoveryLet deadlocks happen, detect via a wait-for graph, then kill/preempt a process.
Ignorance (Ostrich)Assume it's rare enough not to bother — what most general-purpose OSes actually do.

Banker's Algorithm (avoidance) checks, before granting a request, whether the system stays in a safe state — a state with at least one order in which every process could still finish. If no such order exists, the request is delayed.

0x07Talking across boundaries

Inter-process communication (IPC)

Processes have separate address spaces by design — IPC is the sanctioned way for them to exchange data anyway.

Shared Memory

The OS maps the same physical memory region into both processes' address spaces. Fast (no kernel involved after setup), but the processes must synchronize access themselves.

Message Passing

Processes exchange data via send()/receive() through the kernel — pipes, message queues, sockets. Simpler to get right, slower than shared memory.

0x08Concurrency inside a process

Multithreading models

Threads are lightweight processes that share an address space. How user threads map onto kernel threads defines the model.

Many-to-One

UT1
UT2
UT3
KT1

Many user threads map to one kernel thread. Fast to create, but one blocking call blocks all threads.

One-to-One

UT1
UT2
UT3
KT1
KT2
KT3

Each user thread gets its own kernel thread. True concurrency, but thread creation is heavier (Windows, Linux).

Many-to-Many

UT1
UT2
UT3
KT1
KT2

Many user threads multiplexed over a smaller/equal pool of kernel threads — flexible, but complex to implement.

0x09Where things live

Memory management, logical vs. physical address space

A running program only ever sees a logical address — the MMU translates it to a physical one at run time.

// definition

Logical address: generated by the CPU during a program's execution; also called a virtual address. It's what the program itself sees and uses.

// definition

Physical address: the actual location in RAM. The Memory Management Unit (MMU) maps every logical address to one, transparently to the program.

fig — Logical → physical address translation

CPU
Logical Address
MMU (+ base)
Physical Address
Memory
0x0AOne block per process

Contiguous memory allocation

Each process gets one unbroken block of memory. Simple to address, but memory fragments over time.

StrategyRuleTrade-off
First FitAllocate the first hole big enoughFast, but can leave lots of tiny gaps near the front
Best FitAllocate the smallest hole that still fitsLess wasted space per hole, but slow and causes tiny unusable slivers
Worst FitAllocate the largest available holeLeaves a bigger, more reusable leftover hole

External fragmentation (holes scattered between allocations) is the core weakness here — it's the reason paging exists.

0x0BFixed-size chunks

Paging

Logical memory is split into fixed-size pages, physical memory into same-size frames — any page can live in any frame, killing external fragmentation.

fig — Page-table based address translation

Logical Address

Page # (p)
Offset (d)

Page Table

pf0
p+1f3
p+2f1

Physical Address

Frame # (f)
Offset (d)

// definition

TLB (Translation Lookaside Buffer): a small, fast cache of recent page-table lookups — avoids hitting main memory twice (once for the page table, once for data) on every access.

// definition

Internal fragmentation: the wasted space inside the last page of a process, when its size isn't an exact multiple of the page size. Paging trades external for internal fragmentation.

0x0CMeaning-based chunks

Segmentation

Memory is divided by logical unit — code, stack, heap, data — each segment sized to what it actually needs, not a fixed page size.

fig — Segment table + variable-size memory regions

Segment Table (per segment: base + limit)

SegmentBaseLimit
Stack14001000
Heap2600400
Code0600
Data32001100

Physical Memory (variable-size chunks)

Stack1000B
Heap400B
Code600B
Data1100B

Segmentation matches how programmers think (functions, arrays, the stack) but re-introduces external fragmentation — which is why most real systems combine it with paging (segmented paging).

0x0DOverflow valve

Swapping

When physical memory is oversubscribed, the OS temporarily moves an idle process (or its pages) out to disk to free RAM for someone more active.

Process in RAM
Swap out → Disk
…later…
Swap in ← Disk
Process in RAM

Modern OSes mostly swap out individual pages rather than whole processes — this is the mechanism behind virtual memory letting you "use" more RAM than you physically have.

0x0EBeyond RAM

Storage management & disk structure

Disks are addressed as a huge array of logical blocks; the OS decides in what order to service pending requests to minimize costly seek time.

fig — Disk-arm movement under SCAN scheduling

050100150199head start: 50 → sweeps toward 0, reverses, continues to 199 (SCAN)
AlgorithmSweep patternNote
FCFSService in arrival orderFair but can cause long seeks
SSTFNearest request firstLow seek time, can starve far requests
SCANSweep like an elevator, reverse at the endNo starvation, uneven wait at edges
C-SCANSweep one direction only, jump back to startUniform wait time across disk
LOOKLike SCAN but reverses at last request, not disk endAvoids wasted travel to empty ends
C-LOOKLike C-SCAN but jumps to first request, not disk startMost efficient of the family
0x0FWhen the clock is the spec

Real-time systems

Correctness here depends on both the result and the time it arrives in — a perfect answer delivered late can be a failure.

Hard real-time

Missing a deadline is a system failure, full stop. Airbag controllers, pacemakers, flight-control computers.

Soft real-time

Missing a deadline degrades quality but isn't catastrophic. Video streaming, online gaming, audio playback.

Two named scheduling algorithms worth remembering: Rate Monotonic Scheduling (fixed priority — shorter period ⇒ higher priority) and Earliest Deadline First (dynamic priority — whoever's deadline is soonest runs next).

0x10Quick revision

Cheat sheets & imp. points

Formulas, comparisons, and the lines examiners actually look for — skim this the night before.

Memory formulas

QuantityFormula
Logical address space size2^m (m = bits in logical address)
Physical address space size2^n (n = bits in physical address)
Number of pagesLogical space size ÷ Page size
Number of framesPhysical space size ÷ Frame size
Page table sizeNumber of pages × size of one entry
Effective Access Time (EAT)hit_ratio × mem_time + miss_ratio × (mem_time × 2)

One-line "imp." recall per topic

PCB holds everything needed to pause & resume a process; context switch is pure overhead — it does no useful work itself.
Preemptive scheduling needs synchronization primitives; non-preemptive doesn't (a process keeps the CPU until it's done or blocks).
A valid critical-section solution must guarantee mutual exclusion + progress + bounded waiting — memorize all three, not just the first.
Breaking any single one of the 4 necessary conditions is enough to prevent deadlock — you don't need to break all four.
Shared memory = fast but you synchronize; message passing = slower but the kernel enforces the discipline for you.
One-to-one gives real parallelism per thread but is the heaviest to create; many-to-one is cheapest but one blocking syscall stalls every thread.
Logical address space can be, and usually is, larger than physical — that gap is exactly what virtual memory covers.
External fragmentation only happens *between* allocations — compaction (defragmenting) fixes it but costs CPU time to relocate processes.
Page size is always a power of 2 so the logical address split into (page #, offset) is just a bit-shift, not a division.
Segments map to how a programmer thinks about a program (functions/arrays); pages map to how hardware thinks about memory (fixed blocks).
Swap time is dominated by transfer time, which is proportional to the amount of memory being swapped, not the number of processes.
SSTF minimizes seek time locally but can starve requests far from the head; SCAN/C-SCAN trade a bit of speed for guaranteed fairness.
"Real-time" is about deadlines, not speed — a real-time system can be slower than a general one, as long as it's *predictably* on time.

Most-confused pairs

Process vs Thread

A process owns memory/resources; a thread is a schedulable path of execution inside one.

Paging vs Segmentation

Paging = fixed-size, invisible to programmer. Segmentation = variable-size, matches program structure.

Mutex vs Semaphore

Mutex has ownership (only the locker unlocks it). A semaphore is just a counter anyone can signal.

Deadlock vs Starvation

Deadlock: nobody proceeds, ever. Starvation: someone eventually proceeds, just not this someone, for a long time.

Multiprogramming vs Multitasking

Multiprogramming keeps the CPU busy across jobs; multitasking specifically time-slices for interactive responsiveness.

Logical Address vs Physical Address

Logical = what the CPU/program generates. Physical = what actually appears on the memory bus.

Keep this page bookmarked — it's built to be revised, not just read once.