an interactive playground

RTOS, demystified

RTOS = Real-Time Operating System

Linux tries to be fair. An RTOS tries to be on time. That is the whole idea.

Fair is your laptop. Chrome, Spotify, Slack — everyone gets a turn. If the music waits an extra blink, you never notice. On time is different. Some work has a deadline. Miss it, and the failure is not “the app felt slow.” The failure is a car that does not brake, a monitor that does not beep, a network that stays dark because the alarm was still waiting its turn.

Who cares — and why

You, me, and anyone whose life is not a laptop. Most computers you never think about are not trying to be nice. They are trying not to be late.

A laptop is a restaurant

The operating system is a waiter. Every program orders food. The waiter shares the kitchen fairly so nobody starves. That is Linux. That is Windows. That is xv6.

An RTOS is an emergency room

ER = emergency room. A heart attack does not take a number behind a sprained ankle. The urgent patient goes first, even if someone was already being seen. Late here means someone gets hurt.

The internet has ERs too

Under the street, a little computer sits on a fiber-optic cable. If the light dies, that box must scream now — not after it finishes taking notes. Cars, planes, factory robots, hospital gear: same rule.

Below is a tiny C++ kernel that plays by ER rules. Nothing to install. The C++ compiles with g++. Poke it.

Let's go ↓
Chapter 1

Fair vs on time

A general-purpose OS (the Linux on your laptop, or xv6) is that fair waiter: everyone gets a turn. A Real-Time Operating System is the emergency room. The heart attack goes first, even if someone was already being seen.

Same three jobs. Same arrival times. Left side is the restaurant: round-robin, everyone gets a slice of the CPU. Right side is the ER: always run whichever job is most urgent. Watch ALARM — it walks in at tick 4, needs 2 ticks of work, and must be done by tick 7. If it waits in line, it is late. Late is the whole problem.

fair · round robin

General-purpose OS

ALARM waits its turn. Slice = 2 ticks.

waiting to run…
on time · priority

Real-Time OS (the ER)

ALARM jumps the line. Most urgent wins.

waiting to run…

The alarm did not get faster. The policy changed. That is every real-time system in one picture.

Chapter 2

Cut the fiber

Now put the emergency room on a real cable. A fiber-optic cable is a glass line that carries internet traffic as light. An optical network element is the little computer that sits on that cable: it turns light into packets, takes notes (telemetry), and answers the human operator. Then the cable is cut.

The fiber

Think of it as a garden hose, except the water is light, and the light is the internet — video, calls, everything on that path.

A cut

A backhoe hits the hose. The light stops. Until something notices, that path is dead, and nobody upstream knows why.

Loss of Signal (LOS)

LOS is the box saying “the light is gone.” That is the emergency. The alarm has to take the CPU now, not after telemetry finishes its notes.

Hardware raises a Loss-of-Signal interrupt. ISR = Interrupt Service Routine — a tiny bit of code that runs the instant the hardware yells. It does almost nothing: it wakes the LOS task, then gets out of the way. Then pick() must run that alarm immediately. A dark fiber that waits its turn is a network outage. Deadline: finish within 4 ticks of the interrupt.

LINE IN
Network Element
idle
waiting for a tick
Scheduler policy

Highest-priority ready task always wins. LOS (prio 0) will steal the CPU.

pick() this tick

          
LOS deadline
no alarm yet
Cut the fiber to arm a 4-tick deadline.

Flip the toggle to round-robin and cut the fiber again. Same interrupt. Same tasks. The alarm now waits its turn — and misses. That is why Network Element firmware is an RTOS, not a fair scheduler.

Chapter 3

The bug that looks like a scheduler bug

High-priority is blocked. Medium-priority is running. You stare at pick() and it looks broken. It isn't. LOW grabbed a mutex, HIGH needs it, and MED — who doesn't even touch the lock — keeps getting the CPU because LOW is stuck at low priority. HIGH is waiting on LOW. LOW cannot run because MED is "more important" than LOW. That knot is priority inversion.

It grounded Mars Pathfinder in 1997. The fix is almost embarrassing: priority inheritance — while HIGH waits on LOW, LOW temporarily becomes HIGH. MED can no longer sneak in. Toggle it.

waiting to run…

Interview translation: “The scheduler was correct. The lock protocol wasn't.” Inheritance is how FreeRTOS mutexes and Linux rt-mutexes keep a high-priority alarm from dying behind a low-priority holder.

Chapter 4 · The Real Deal

Here's the actual C++.

Everything above is a visualization of one file: kernel.cpp. It compiles on Linux with nothing but g++. The playground and the binary implement the same policy — pick(), notify() from an ISR, mutexes, inheritance.

On any Linux box
g++ -std=c++17 -Wall kernel.cpp -o tinyr-tos && ./tinyr-tos
./tinyr-tos invert
./tinyr-tos inherit

Download kernel.cpp · same file the playground is running in your head.

This kernel

pick() — highest effective priority wins. 0 = highest.

Linux PREEMPT_RT

pthread_setschedparam(t, SCHED_FIFO, {99 - prio}) — same policy, real threads.

FreeRTOS / a Network Element

Tasks + ISRs + mutexes. The alarm is a high-priority task notified from the line interrupt.

Loading kernel.cpp…

You made it.

A general-purpose OS shares the CPU fairly. An RTOS shares it by urgency. You watched a fiber-cut ISR notify a C++ task, watched that task preempt telemetry, met a deadline, and saw priority inversion lie to you — then vanish when the lock inherited priority. That is the kernel of every Network Element, robot, and car.

Already poked the Unix side? xv6, demystified →

Run it back ↑