Skip to content
Tech Interview Prep home
Technical interview guide

RTOS & Task Scheduling

How a real-time operating system schedules multiple tasks with timing guarantees, and the classic concurrency hazards — priority inversion, deadlock — that come with it.

Read
60 min
Practice MCQs
25
Interview QA
25
Edition
v3
Editorial status
Review pending

Scope: CMSIS-RTOS2 current API; CMSIS-RTX5 current configuration; current FreeRTOS and Zephyr scheduling guidance reviewed 2026-09-04.

Overview

Curated: · Written: · Reviewed:

A real-time operating system schedules runnable tasks according to a documented policy; it does not make arbitrary workloads meet deadlines. Each task alternates among running, ready, and blocked states, and correctness depends on release patterns, priorities, execution-time bounds, blocking, interrupt interference, kernel configuration, and resource capacity. The highest-priority ready task is commonly selected, while equal-priority and cooperative behavior depends on the specific port and settings.

Priority should express deadline or response urgency derived from analysis, not organizational importance. Rate-monotonic and deadline-based analyses require explicit assumptions; sporadic bursts, shared-resource blocking, non-preemptible sections, interrupts, cache and bus interference, and overload must be included. Priority inversion occurs when urgent work waits behind a lower-priority resource owner; priority inheritance can bound some cases but does not cure bad locking topology.

Tasks should block on bounded queues, flags, semaphores, or notifications instead of polling. Mutexes protect exclusive resources and have ownership semantics; semaphores represent counts/events and are not interchangeable with mutexes. ISR APIs, timer callbacks, cancellation, object lifetime, queue overflow, stack budgets, watchdogs, tick wrap, and low-power timekeeping require explicit contracts.

The production invariant is deadline-with-state fidelity: every job has an attributable release, ready/block/run history, deadline, resource wait, completion or drop outcome, and bounded recovery under declared load. Release-build traces, response-time maxima, utilization, queue and stack high-water marks, missed-deadline counters, watchdog evidence, and overload tests must validate the scheduling model.

Priority inversion is a measured blocking term, not a rumour. A 1 kHz control task at priority 4 waits on a mutex held by a logging task at priority 1 while a medium-priority network task at priority 2 runs for 8 ms. Without inheritance the control task’s response time is 8 ms plus its own 120 µs WCET — eight periods late. With priority inheritance the logger runs at 4 for the critical section (40 µs) and the control task meets a 500 µs deadline. Rate-monotonic utilization of 0.69 on three tasks does not include that 8 ms; any analysis that stops at CPU share is incomplete.

vTaskDelay(10) after work drifts. A 10 ms period task that runs 3 ms and then delays 10 ticks from “now” actually periods at 13 ms; after 1 s it has released 77 times instead of 100, and a 10 Hz plant loop is now 7.7 Hz. vTaskDelayUntil against an absolute tick, with wrap-safe subtraction, keeps the phase. Tickless idle wrapping a 32-bit tick at 1 kHz overflows at 49.7 days; if the wrap is not handled, a delayed task sleeps for ~49 days. Stack overflow hooks that only log from the overflowed task cannot run: the stack is already gone. A painted watermark checked from a high-priority watchdog task, plus MPU guard regions of 32 bytes below each stack, catches the 1,540 / 1,536 byte case before the heap is corrupted.

ISR APIs matter. xQueueSend from an ISR without FromISR and without yielding the higher-priority waiter leaves that waiter blocked until the next tick — 1 ms of extra latency on a 1 kHz tick. Queue-full policy must be explicit: drop newest, drop oldest, or overwrite a named slot, each with a counter. Equal-priority round-robin at 1 ms timeslice on two CPU-bound tasks of 4 ms WCET each will miss a 5 ms deadline that a strict priority split would meet. Record the policy, the measured blocking, and the missed-deadline counter on the release image under a fault injector, not on a debugger that stops the tick.Timer daemon priority is a hidden scheduling class. FreeRTOS timers run in a task whose priority is a #define; a 50 ms software timer that stops a motor, running below a CPU-hungry GUI at the same priority as idle, fires 400 ms late. Put the timer task above any work that must not delay timed safety actions, or do not use software timers for those actions — use a hardware timer ISR that only sets a flag. Tickless idle that stops SysTick and programs an RTC compare must convert remaining ticks with the same frequency; a 32.768 kHz RTC and a 1000 Hz tick misconverted by integer divide (32768/1000 = 32) accumulates 24 ms per second of sleep and every timeout is 2.4% slow.

Mutexes have owners; counting semaphores do not. Using a counting semaphore as a lock lets a task "give" a lock it never took, and a priority inheritance story does not apply. Queue overflow: a 16-slot 12-byte command queue at 200 commands/s needs 16/200 = 80 ms of consumer slack; a 100 ms flash erase in the consumer overflows 4 commands. Count overflows and apply backpressure to the producer, including in the ISR that would have sent. Cooperative slices that run 12 ms in a 10 ms period are unbounded WCET; break the work or preempt.

Scheduler verification is a release-image ritual that starts at a trace and ends at a missed-deadline counter. Record SYSCLK, wait states, compiler flags, .map sizes, painted stack high-water marks, ISR GPIO timing, logic-analyzer traces of CS/SCK/SDA, current-shunt waveforms at not less than 100 kHz, reset-cause and fault registers, and the boot slot/security counter after every power-loss injection. A pass is a number that can be recomputed from those artifacts: flash LOAD versus FLASH LENGTH, ISR high-water versus period, Stop current versus the schematic budget, confirm window versus the health checks, and disable-to-deny for debug and keys. If the only evidence is a green LED, a UART log, or a debugger session on an -O0 build, the claim is unpublished. Repeat the same measurements at the temperature and voltage corners the datasheet allows, because flash wait states, Stop leakage, crystal error, and brownout thresholds all move, and a 25 °C passing suite is not a 85 °C passing suite.

Idle-hook sleep that calls WFI without the kernel's tickless accounting stops the tick while a vTaskDelayUntil waiter still counts missing ticks as not-yet-due, so a 10 ms waiter can sleep 50 ms if a 40 ms Stop was not converted. Either use the port's documented tickless idle or do not sleep in the idle hook. Starvation tests: pin a medium task ready forever and prove the lowest real-time task still meets its deadline, or the priority table is fiction.

Worked example: 8 ms inversion misses a 500 us deadline

1 kHz control task at priority 4 waits on a mutex held by a logger at priority 1. A network task at priority 2 runs 8 ms.

mutexcontrol response500 us deadline
no inheritance8 ms + 120 us WCETmiss (eight periods late)
priority inheritance, 40 us critical sectionabout 160 usmeet

CPU utilization of 0.69 does not include that 8 ms. Inheritance is a measured blocking bound, not a slogan.