Musings on processes

Computers can only run one program at once. The concept of a program does not really exist at the level of the CPU; we merely have the current state of the machine (registers and memory contents) which determines the next state that will be executed. The program counter register keeps track of the address of the currently executing instruction. The current program is merely whatever instructions are currently being executed.

Processes were the solution to running more than one program at the same time. This is implemented by simulating the environment of a single program running on a dedicated computer.

To do this, we need to give each program a private, virtual address space so that it can pretend it has exclusive use of the memory and so that the sections of the program can be mapped to the expected addresses. We also want to prevent programs from reading or writing memory belonging to other programs. This is implemented using segmentation (offset/limit registers) or page tables (memory-management unit).

We also need to periodically interrupt execution so that other programs have a chance to run. This is implemented using a countdown timer which causes an interrupt line on the CPU to be raised after some time has passed, causing execution to be diverted to an interrupt handler. The handler saves the CPU state of the currently executing process, determines which process to run next (this is called "scheduling"), restores the CPU state of the next process, and then continues execution at the point that it had previously been interrupted.

The CPU has no concept of the current process being executed. Process switching is a software hack. This appeared to work for a long time until it was realised that modern CPUs had lots of internal, hidden state that the operating system was not aware or in control of, that allowed information leaks between processes. Further hacks were added in an attempt to flush this state away when switching between processes. Unfortunately this is expensive as caches and buffers that enable the CPU to run faster are discarded.

For the ability to run multiple programs we gave up determinism since we don't know when our program will be interrupted or how long it will be able to run before being interrupted again. We don't reliably know how much memory is available since this can change dynamically depending on what other processes are running and what memory they are using. Page swapping adds further nondeterminism as memory access could cause our program to be stalled for a long time while a page is read from storage. We have built an unreliable system on top of a reliable one.

Interrupts are the original sin that introduced indeterminism and allowed the process switching hack to be implemented in the first place.