Operating system fundamentals
The operating system is what shares out the processor, the memory and the peripherals among programs that believe they own the machine. Understanding how it does so explains almost every odd behavior of a program.
01The one that shares out the machine
A program is written as if it owned the processor, the memory and the peripherals. It does not: dozens are running at once. The operating system maintains that illusion and shares out what there is.
| Resource | What the program sees | What is really there |
|---|---|---|
| Processor | One all to itself | A few cores shared out in slices of milliseconds |
| Memory | A continuous space starting at address zero | Pages scattered in RAM, and some on disk |
| Disk | Files and folders | Numbered blocks on a device |
| Peripherals | A file that is opened and read | Hardware registers and interrupts |
To sustain that illusion the processor has two modes: user mode, where programs run and certain
instructions are forbidden, and kernel mode, where the operating system runs. Switching from one to the other is done by a
system call, which is a deliberate interrupt. Every
open, read or write crosses that border, and that is why they cost much more
than an ordinary function.
02Processes and threads
| Process | Thread | |
|---|---|---|
| Memory | Its own, isolated | Shares the process’s |
| Cost to create one | Considerable | Little |
| If it fails | Only it dies | It takes the whole process down with it |
| Communication | Through pipes, sockets, shared memory | Common variables, with care |
Each process goes through a few states: ready when it can run, running when it has the processor, and blocked when it is waiting for something —data from the disk, a byte from the serial port—. That third state is the key: a blocked process uses no processor, and that is why a machine can have hundreds of programs open without breaking a sweat.
03Scheduling
When there are more ready processes than cores, someone decides who goes next. That policy is the scheduler, and two conflicting numbers depend on it: the turnaround time —how long a job takes from start to finish— and the response, which is what the person sitting in front of the machine perceives.
The same four processes, shared out under different policies. Look at the diagram and compare the averages.
Every time the scheduler switches processes, all the registers of the outgoing one have to be saved and those of the incoming one loaded: a few microseconds, plus the invisible cost of the cache being full of someone else’s data. With a very small quantum the machine spends the day switching context instead of working; with a very large quantum, interactive response is lost.
04Virtual memory
Each process sees addresses that are not those of the RAM. The processor’s memory management unit translates each virtual address into a physical one by consulting a page table, and three valuable things come out of that:
- Isolation. A process cannot touch another’s memory, because its table does not even name it. That is why a program that hangs does not drag down the whole machine.
- Memory larger than RAM. Pages that are not in use go down to disk. If the program touches them again, a page fault occurs and the system brings them back.
- Sharing without copying. Two processes that use the same library point to the same physical pages.
If programs ask for more active memory than there is, the system spends its time swapping pages in and out: this is thrashing. The machine seems dead but the processor is almost idle; what is saturated is the disk. It is recognized right away because the disk activity indicator never stops.
05Concurrency
Two threads that touch the same variable without coordinating produce the hardest error to find in
all of programming. counter++ is not an atomic operation: it is three —read, add,
store— and between them the scheduler can switch threads.
| Tool | What it is for |
|---|---|
| Mutual exclusion (mutex) | So that only one thread at a time enters the critical section |
| Semaphore | Counting available resources; synchronizing producer and consumer |
| Condition variable | Waiting for something to happen, without using the processor |
| Atomic operations | A shared counter, without blocking |
| Queue between threads | The safest way: nobody shares state, messages are passed |
Two threads, each holding a lock, waiting for the other’s: neither ever advances. Four conditions are needed at once, and breaking one is enough to avoid it. The practical rule is to always take the locks in the same order throughout the program.
06What changes in real time
An ordinary operating system aims for everything to run fast on average. A real-time one aims for something different: for a response to always occur before a deadline. An excellent average with an unpredictable worst case is no good for controlling a motor.
| General purpose | Real time | |
|---|---|---|
| Goal | Good average | Bounded worst case |
| Scheduling | Fairness and response | By priority, with preemption |
| Interrupt latency | Variable | Guaranteed, in microseconds |
| Examples | Linux, Windows | FreeRTOS, Zephyr, QNX |
On a microcontroller, a system like FreeRTOS provides prioritized tasks, queues and semaphores in a few kilobytes. Priority inversion —a low-priority task holding a lock that a high-priority one needs— is the classic problem, and it is solved with priority inheritance.
07In the lab
With top or the task manager, observe states, memory and processor usage.
Launch an infinite loop and see what changes; then one that only waits for input and compare.
Two threads that each increment a shared counter a million times. Verify that the result is not two million, and then fix it with a mutex.
One task that blinks an LED every 500 ms and another that reads the serial port, communicating through a queue. Use an oscilloscope to check whether the blinking shifts when data arrives: that is the latency.
08Common mistakes
- Believing that
counter++is atomic. - Taking locks in different orders in different parts of the program: deadlock guaranteed.
- Waiting with an empty loop instead of blocking: it burns an entire core doing nothing.
- Assuming that more threads is faster. If the work is disk or network bound, it is not.
- Confusing concurrency with parallelism. Concurrent means they advance in turns; parallel, that they run at the same time on different cores.
- Using an ordinary system where a real-time one is needed, and finding out in the field.
09Self-assessment
What is the difference between a process and a thread?
A process has its own isolated memory; the threads of a process share it. Creating a thread costs much less, but if one corrupts the memory it takes all of them down.
Why does a system call cost more than an ordinary function?
Because it crosses from user mode to kernel mode: the context has to be switched, the parameters validated, and then it returns.
What happens with a quantum that is too small in Round-Robin?
The system spends more time switching context than executing: useful work drops even though the response seems good.
What is a page fault?
An access to a page that is not in RAM. The system brings it from disk and resumes the process, which notices nothing except the delay.
How is a deadlock avoided in practice?
By always taking the locks in the same order throughout the program, and using timeouts when trying to take them.
What does a real-time operating system guarantee that Linux does not?
A bounded worst case: the response always occurs before the deadline, not just on average.
10Further reading
- Abraham Silberschatz, Peter Galvin and Greg Gagne. Operating System Concepts. 10th ed. (Spanish edition, “Fundamentos de sistemas operativos”), Wiley, 2018. The classic text for the subject: processes, scheduling, memory and concurrency.
- Remzi and Andrea Arpaci-Dusseau. Operating Systems: Three Easy Pieces. Arpaci-Dusseau Books. Free online. It explains virtualization, concurrency and persistence better than any other, and it is free.
- Andrew S. Tanenbaum. Modern Operating Systems. 4th ed. (Spanish edition, “Sistemas operativos modernos”), Pearson, 2014. Rigorous and complete, with good chapters on embedded systems.
- FreeRTOS documentation. Mastering the FreeRTOS Real Time Kernel. Real Time Engineers Ltd. Real time applied to the microcontroller, with examples you can run.