Skip to content

What an OS is and why it exists

When you write fopen("data.txt"), you do not need to know the disk model, the sector number, or that at this very second two hundred other processes are also accessing the disk. When you write malloc(1024), nobody asks the neighboring programs for permission.

Hardware gives you none of this convenience. It is created by a specific program that sits between your code and the hardware. This whole course is about how that program works on the inside.

People usually say that an operating system manages resources. That is true, but incomplete.

First, the OS invents convenient concepts where there are none. Hardware offers a terrible interface: controller registers, sector numbers, interrupts. You can work with it directly, but you really do not want to. So instead the OS gives you a file, a process, a socket. None of these things exist in hardware; they are entirely made up.

The second thing an OS does is allocate resources. There is one CPU and two hundred programs; memory is finite and appetites are not. Someone has to decide who gets how much, and make sure one program does not ruin things for the others.

Both jobs come down to the same thing: isolation. An abstraction that can be bypassed is worthless, because a program would simply write to the disk directly and wreck everything the OS has built. So the OS has to be the only one allowed to talk to the hardware at all.

System layers from applications to hardware, with a hardware-enforced boundary between user mode and kernel modeapplicationsbrowser, compiler, your codelibraries and runtimeslibc, JVM, Node: still user modeoperating system kernelprocesses, memory, files, networking, drivershardwareCPU, memory, disks, network cardsuser modekernel modea system call is the only legal crossing ↓
Libraries, despite being called “system” libraries, run in user mode. They are just convenient wrappers around system calls; the real boundary lies below them.

The CPU can execute code in at least two modes. In kernel mode all instructions are available: you can reprogram the MMU, disable interrupts, access a device port. In user mode, an attempt to do the same raises an exception.

The important part is that this is a property of the hardware, not an agreement between programmers. A program cannot “decide” to switch to kernel mode. It can only ask the kernel to do something on its behalf, and that is done with a system call (module 3).

This makes it clear what is part of the OS and what is not. libc is not the kernel: it runs in user mode. The shell is an ordinary program too. A driver, on the other hand, belongs to the kernel, because it talks to the hardware directly.

You can read the history of operating systems as a list of dates, but then it explains nothing. It is far more useful to look at what exactly was missing at each point.

In the fifties, machine time was scarce. A computer cost as much as a factory, and idle time between jobs was unacceptable. That is how batch processing appeared: jobs are put in a queue, a monitor runs them one after another, no operator needed. The monitor became the first program that controls other programs.

In the sixties it turned out that the CPU spent most of its time doing nothing while a job waited for tape. The answer was multiprogramming: keep several jobs in memory and switch to another one while the first is waiting. Two topics that take up half of this course grew straight out of that: memory protection (jobs must not see each other) and scheduling (module 7).

Next, the person at the terminal became the annoyance: in batch mode you had to wait a day for results. The solution was time-sharing, where everyone gets a CPU quantum often enough for the work to feel interactive. Multics grew out of this idea, and Unix grew out of frustration with Multics’s complexity.

In the eighties the computer became personal, the shortage of users disappeared, and for some reason the need for protection disappeared along with it. Early MS-DOS and Mac OS had neither memory protection nor preemptive multitasking, so a single bug could hang the machine. It took the next fifteen years to bring those properties back.

In the 2000s the scarce thing became server utilization. One application per server was wasteful; several on one server led to dependency conflicts. At first the answer was virtualization, then containers (module 17).

And then CPU clock speeds stopped growing. Instead of faster cores, manufacturers started adding more cores, and laptops and phones added one more constraint: battery charge. So the scheduler now takes into account not only speed but also energy use, NUMA topology and heterogeneous cores.

All of this can be seen on a single timeline: in the appendix “History of operating systems” every system sits where it appeared and is connected to the ones it grew out of.

The phrase “operating system” means very different things depending on what it manages.

Class Examples What drives the design
Embedded, no OS microcontroller firmware a few kilobytes of memory, one task
RTOS FreeRTOS, Zephyr, QNX predictability matters more than throughput
Mobile Android, iOS battery, application isolation, permissions
Desktop Windows, macOS, Linux response time, hardware diversity
Server Linux throughput, uptime
Hyperscalers hypervisors, orchestrators thousands of machines as one resource

What sets a real-time system apart is not speed but predictability. An RTOS guarantees that a response will come no later than a certain deadline. For a car’s brakes, a steady 10 ms is better than “usually one millisecond, but sometimes a hundred”.

Terminal window
uname -a; cat /proc/version

The kernel version, the architecture and what it was built with. Note that the kernel has its own version, unrelated to the distribution version.

Terminal window
ls /boot/vmlinuz-* 2>/dev/null; lsmod | head -5

The kernel sits on disk as an ordinary file. lsmod shows the modules loaded into it at run time: drivers and subsystems that do not have to be kept inside.

Terminal window
ps -p 1 -o pid,comm,args

The process with PID 1 is the first one the kernel starts in user mode, and everything else in the system descends from it (module 5).

Terminal window
ltrace -e 'malloc+free' -- /bin/echo hi 2>&1 | head -5
strace -c -- /bin/echo hi 2>&1 | tail -12

The first command shows library calls, the second shows system calls. The difference between these two lists shows the boundary from the figure above.

“The OS is what I see on the screen.” A graphical shell consists of ordinary user-mode programs. A server without a monitor has a fully functional OS and not a single window.

“The OS manages resources.” It does, but that is half the job. The other half is creating abstractions that simply do not exist in hardware.

“The kernel is slower than a program because it adds a layer.” The kernel does not stand in the path of every operation. The CPU executes computations directly, and the kernel steps in only on system calls, interrupts and exceptions.

“Real-time systems are the fastest.” They are the most predictable. In average throughput an RTOS often loses to Linux.

“Linux is an operating system.” Strictly speaking, Linux is a kernel. What you install is called a distribution: the kernel plus libc, a shell, an init system and thousands of packages.

Check yourself

1. What are the two main jobs of an operating system?
2. Why can a program not switch to kernel mode on its own?
3. Which hardware limitation gave rise to multiprogramming?
4. What fundamentally distinguishes a real-time system from an ordinary one?
5. Is libc part of the kernel?
6. Why did Unix displace earlier systems and survive to this day as Linux, macOS and Android?