Skip to main content

Four Fundamental OS Concepts

Source: UC Berkeley CS162, Fall 2020/2021 - Prof. John Kubiatowicz, Lecture 2

CS162 Lecture 2 - Four Fundamental OS Concepts

This lecture lays the foundation for the whole course. It starts from a single question - what does an operating system actually do? - and then introduces the four ideas everything else is built on: the thread, the address space, the process, and dual-mode operation. Get these four straight and the rest of the course (scheduling, memory, concurrency) is variations on them.

Taming complexity: the OS as an abstraction layer

Hardware is a pile of complexity - many cores, memory hierarchies, dozens of devices, each with its own quirks. An operating system sits between the hardware and your program and offers clean, easy-to-use abstractions of that messy physical machine. It plays three roles at once: a referee that manages sharing and protection between programs, an illusionist that makes each program feel like it has the machine to itself, and glue that provides common services (storage, windowing, networking).

Three-layer stack: Application on top, Operating System in the middle exposing an Abstract Machine Interface upward and a Physical Machine Interface downward, Hardware at the bottom
The OS turns the physical machine interface (what the hardware really offers) into an abstract machine interface (what programs get to see). Every concept in this lecture is one of those abstractions.

What a program actually is

To see what the OS has to virtualize, recall from architecture what running a program means: the processor repeats a fetch/decode/execute cycle - fetch the instruction at the program counter, decode it, execute it (reading and writing registers and memory), advance the PC, and repeat. The complete state of a running computation at any instant is just its registers (including the PC and stack pointer) plus the memory it can touch.

Program execution: a register file and Fetch/Execute unit reading instructions and data from memory, with the execution sequence fetch, decode, execute, write results, advance PC, repeat
A running program is registers + memory, driven by the fetch/decode/execute loop. If you can save and restore that state, you can stop a program and resume it later as if nothing happened - which is exactly what the OS does.

Concept 1: the thread

The OS gives each running activity the illusion of its own processor. In reality one core is time-multiplexed among many, but from the programmer's view each thread has a dedicated (virtual) CPU with its own registers.

Three virtual CPUs (vCPU1, vCPU2, vCPU3) drawn above a single Shared Memory box, labelled Programmer's View
The illusion: several virtual CPUs sharing memory. The programmer writes code as if each thread runs on its own processor.

A thread is a single, sequential stream of execution - one PC threading its way through the code. The magic that maintains the illusion is the context switch: the OS saves the current thread's registers into memory, loads another thread's saved registers, and jumps to its PC. The saved state lives in a per-thread structure (a thread/process control block).

Two virtual CPUs mapped to one real core over time; text explaining that on a switch the OS saved PC and SP into vCPU1's thread control block and loaded them from vCPU2's, triggered by a timer, voluntary yield, or I/O
What really happens on a switch: the OS saves the outgoing thread's PC, SP and registers into its control block, loads the incoming thread's from memory, and resumes. Switches are triggered by a timer, a voluntary yield, or I/O.
Several processes (Proc 1, Proc 2, ... Proc n) above the OS, each with its own stack, heap, static data and code region in memory
Multiprogramming: many independent streams of control, each with its own stack, kept ready to run. The OS holds all their saved states and picks who runs next.
The thread
  • A thread is one sequential execution context: a PC plus the registers and stack that go with it.
  • Its complete state can be saved and restored, so a thread can be paused and resumed transparently.
  • The OS keeps that state in a control block in kernel memory and multiplexes many threads onto the real CPU(s) via context switches.

Concept 2: the address space

The second concept answers "what memory can a thread touch?" An address space is the set of memory addresses a program may reference, plus the state associated with them. Each program is written as if it owns a big, private range of memory.

A processor with PC and SP registers pointing into an address space laid out as stack (high addresses), heap, static data, and code segment (low addresses)
An address space in a picture: code and static data near the bottom, the heap growing up, the stack growing down from the top. The PC points into code; the SP points into the stack.
How big is an address space?
  • 32-bit processor - 2^32 addresses, about 4 billion bytes (4 GiB).
  • 64-bit processor - 2^64 addresses, about 18 quintillion bytes - far more than any real machine has RAM for, which is the whole point: the address space is virtual.

For this to be safe, the hardware must stop one program's addresses from reaching another's memory. The simplest scheme is base and bound: the hardware adds a per-program base to every address and checks it against a bound, so a program can only touch its own region and cannot see the OS or other programs.

Base and Bound: a program address is compared against a Bound and offset by a Base register before reaching physical memory; annotations note it protects the OS and isolates the program but requires a relocating loader
Base and bound: every address is offset by Base and checked against Bound in hardware. It isolates programs cheaply, but requires relocating the program at load time and cannot grow regions independently.

Real machines generalise this to paged virtual memory: the address space is split into fixed-size pages, and a per-process page table maps each virtual page to a physical frame (or to disk). This gives each process its own private, relocatable address space without contiguous physical memory.

Paged virtual address translation: a virtual address split into page number and offset, the page number indexed into a page table to produce a physical frame, combined with the offset to address physical memory
Paged translation: split the virtual address into a page number and an offset, look the page up in the page table, and combine the resulting frame with the offset. This is how modern OSes give every process its own address space.

Concept 3: the process

Put a thread and an address space together and add the OS state that protects them, and you get a process - the OS's unit of protection and resource ownership. A process is one address space plus one or more threads running inside it, plus everything the OS tracks on its behalf (open files, and so on).

Slide titled Third OS Concept: Process
The third concept: a process is the protected container - an address space plus its threads and OS-managed resources.
A single-threaded process with one thread, next to a multithreaded process where several threads share the same code, data and files but each has its own registers and stack
One process, one address space - but possibly many threads. The threads share the code, data and open files; each still has its own registers and stack.

Why bother with the process boundary at all? Protection.

Slide 'Protection and Isolation' listing reliability, security and privacy, and fairness as reasons for processes, with mechanisms address translation and hardware privilege levels
Processes exist for reliability (a bug can only corrupt its own memory), security (one process can't read another's data), and fairness. The enforcing mechanisms are address translation plus hardware privilege levels.
The process
  • A process = one address space + one or more threads + the OS state (open files, etc.) associated with them.
  • It is the OS's unit of protection and isolation: each process sees only its own memory.
  • A single process can run multiple threads, which share the address space but each keep their own registers and stack.
Threads inside a process are not protected from each other

Protection is a property of the address-space boundary, i.e. the process. Two threads in the same process share all of memory by design, so one can freely stomp on another's data. That is exactly why concurrency inside a process is dangerous and needs synchronization - a topic the next unit is entirely about.

Concept 4: dual-mode operation

The final concept is what makes the other three enforceable. The CPU runs in one of (at least) two modes: user mode, where dangerous operations are forbidden, and kernel mode (supervisor/privileged mode), where the OS runs with full access to hardware. Only carefully controlled transitions move between them.

A dome split into an outer User Mode ring with limited hardware access and an inner Kernel Mode core with full hardware access; arrows labelled syscall, interrupt, exception and exit cross between them
User mode has limited hardware access; kernel mode has full access. The only ways in are a syscall (deliberate), an interrupt (a device), or an exception (a fault); the kernel returns to user mode when done.
Dual-mode operation
  • The CPU has a hardware mode bit: user (restricted) vs kernel (full privilege).
  • Privileged operations (changing the page table, disabling interrupts, touching devices) are only allowed in kernel mode.
  • The only entries to the kernel are a system call, an interrupt, or an exception - each an "unprogrammed control transfer" to a fixed, OS-controlled address.
Why user code can't just jump into the kernel

The transition into kernel mode does not let user code pick where execution lands. Each entry (syscall/interrupt/exception) vectors to an address the OS chose in advance. If a program could set the target itself, it would run arbitrary code with full privilege - so the "unprogrammed control transfer" is deliberately out of the program's hands.

Tying it together

With all four concepts in place, loading a program is straightforward: the OS sets up an address space (here via base and bound), copies in the code and data, initialises the stack, records the process's saved registers, and then switches into it in user mode. Everything after that is the same four ideas working together.

The OS loading several processes: each process gets Base, Bound, saved user PC and registers, and its own code/data/heap/stack region in memory
Loading a process end to end: give it an address space (Base/Bound), lay out its code, data, heap and stack, record its saved PC and registers, and dispatch into user mode. Thread + address space + process + dual mode, all at once.

Recap

  • The OS is a referee, illusionist, and glue that turns messy hardware into clean abstractions.
  • A thread is a single execution context (PC + registers + stack) that the OS can save, restore, and multiplex onto real CPUs via context switches.
  • An address space is the private set of memory a program can touch, enforced by hardware (base/bound, then paged virtual memory).
  • A process is an address space plus its threads plus OS state - the unit of protection and isolation.
  • Dual-mode operation (user vs kernel) plus controlled transitions is what makes that protection enforceable.
  • Next: how these are exposed to programs, starting with the process API - fork, exec, wait, exit.