KRN-IRQ - Interrupts, Exceptions, Critical Sections, Scheduler Lock¶
Group KRN-IRQ. Design: docs/specs/SPEC-002-interrupts-and-critical-sections.md. Related groups: KRN-SCH (v0.1 §4, 03 §2), KRN-RT (v0.1 §4.10), API (SPEC-001).
KRN-IRQ-001 to 003 and 010 to 016 originate in the v0.1 specification (§3.7 and §6.6) and are restated here as the authoritative copy; their statements are unchanged. Numbers 004 to 009 were never assigned and stay unassigned. New requirements start at 017.
Requirements¶
KRN-IRQ-001 No blocking in interrupt context¶
Statement. Interrupt context shall not perform blocking operations.
Rationale. An ISR has no thread to block; blocking there corrupts the scheduler’s model of who is running.
Status. Accepted (v0.1)
Verification. Test: tests/conformance/misuse/ calls each thread-only function from an ISR in checked and release builds (API-015).
Trace. v0.1 §3.7; SPEC-002 §3.1; SPEC-001 §5.2
KRN-IRQ-002 Interrupt context is distinguishable¶
Statement. Interrupt context shall be distinguishable from thread context.
Rationale. Every context-class check and every ISR-safe code path depends on it.
Status. Accepted (v0.1)
Verification. Test: emb_context() returns EMB_CONTEXT_ISR inside every handler level and EMB_CONTEXT_THREAD outside, on every port.
Trace. v0.1 §3.7; SPEC-002 §2; SPEC-001 §5.1
KRN-IRQ-003 Wakeup from an interrupt permits scheduling before thread resume¶
Statement. An interrupt that makes a higher-priority thread READY shall permit scheduling before returning to thread execution when preemption is enabled. Rationale. This is the definition of preemptive scheduling driven by events rather than ticks. Status. Accepted (v0.1) Verification. Test: ISR wakes a higher-priority thread; that thread runs before the interrupted thread’s next instruction (measured by a sequence counter). Trace. v0.1 §3.7; SPEC-002 §6; KRN-SCH-020
KRN-IRQ-010 ISR-safe operations are explicit¶
Statement. ISR-safe kernel operations shall be explicitly identified.
Rationale. Callers cannot guess; the annotation is the contract.
Status. Accepted (v0.1)
Verification. Analysis: every public function has a @ctx tag (API-003); the ISR-safe set is the functions tagged thread isr.
Trace. v0.1 §6.6; SPEC-001 §9; API-014
KRN-IRQ-011 ISR-safe operations never block the caller¶
Statement. An ISR-safe operation shall not require the caller to block.
Rationale. Follows from KRN-IRQ-001 for the kernel’s own implementation paths.
Status. Accepted (v0.1)
Verification. Analysis: @ctx thread isr functions are @blocks no, or @blocks timeout with a documented ISR-safe EMB_NO_WAIT path.
Trace. v0.1 §6.6; API-014
KRN-IRQ-012 Nesting depth is observable¶
Statement. Nested interrupt depth shall be observable to the kernel when nesting is supported.
Rationale. The outermost-exit rule, stack sizing, and diagnostics all need the depth.
Status. Accepted (v0.1)
Verification. Test: emb_irq_nesting_depth() equals the actual depth in a nested-interrupt test on Cortex-M, RISC-V with nesting, and native.
Trace. v0.1 §6.6; SPEC-002 §7.1
KRN-IRQ-013 Reschedule during nested handling stays pending¶
Statement. A reschedule requested during nested interrupt handling shall remain pending until a legal thread-resume boundary. Rationale. Switching threads from inside a nested interrupt would leave an interrupted handler’s frame on the wrong stack. Status. Accepted (v0.1) Verification. Test: nested ISR wakes a higher-priority thread; the switch occurs only after the outer handler returns. Trace. v0.1 §6.6; SPEC-002 §6.1; KRN-SCH-021
KRN-IRQ-014 Bounded kernel masking¶
Statement. Interrupt masking used by kernel internals shall have bounded duration.
Rationale. Kernel masking is the floor of every interrupt latency figure.
Status. Accepted (v0.1)
Verification. Demonstration: CONFIG_EMB_IRQ_LOCK_STATS under the stress suite on HIL reports the maximum; it is published per release.
Trace. v0.1 §6.6; SPEC-002 §4.2, §10; KRN-RT-003
KRN-IRQ-015 No controller assumption in the generic kernel¶
Statement. The generic kernel shall not assume a specific interrupt-controller architecture.
Rationale. NVIC, PLIC, CLIC, AVR’s fixed vectors, and the simulator are all targets.
Status. Accepted (v0.1)
Verification. Analysis: kernel/ includes no architecture header and references no controller register (02 §5 dependency check).
Trace. v0.1 §6.6; SPEC-002 §8
KRN-IRQ-016 Documented entry, exit, save, and reschedule behavior¶
Statement. Architecture documentation shall define interrupt-entry, interrupt-exit, context-save, and rescheduling behavior.
Rationale. A port’s correctness is reviewable only against a written description.
Status. Accepted (v0.1)
Verification. Inspection: each docs/ports/<arch>.md has the sections named in 05 §9.
Trace. v0.1 §6.6; SPEC-002 §13
KRN-IRQ-017 Two interrupt classes¶
Statement. The kernel shall distinguish kernel-aware interrupts, which it may mask and whose handlers may call ISR-safe API, from kernel-independent interrupts, which it shall never mask and whose handlers shall call no kernel function. The boundary shall be the configured level CONFIG_EMB_IRQ_KERNEL_LEVEL. The kernel-independent class shall be available only on architectures with interrupt priority masking and shall be rejected at configuration time elsewhere.
Rationale. Zero-latency interrupts are a real-time requirement the kernel can only meet by staying out of their way (v0.1 §6.3).
Status. Accepted 2026-10-07
Verification. Test: with the class enabled on Cortex-M, a kernel-independent interrupt fires inside a kernel critical section and its handler runs within hardware latency; Analysis: Kconfig rejects CONFIG_EMB_IRQ_ZERO_LATENCY on Armv6-M, AVR, and native.
Trace. SPEC-002 §3
KRN-IRQ-018 Key-based, nestable critical sections¶
Statement. The kernel shall provide emb_irq_lock() returning the previous mask state and emb_irq_unlock(key) restoring exactly that state, callable from thread, interrupt, and pre-kernel context, nestable, with unlocks in reverse order of locks. Both shall be O(1), shall never block or yield, and shall act as compiler barriers.
Rationale. Key-based masking nests for free, works identically from ISRs, and maps to one or two instructions on every architecture (SPEC-002 §4.1).
Status. Accepted 2026-10-07
Verification. Test: nesting test restores the outer state exactly; Analysis: the inline wrappers carry a "memory" clobber on all three compilers.
Trace. SPEC-002 §4.1; KRN-RT-003
KRN-IRQ-019 Critical sections are per CPU¶
Statement. emb_irq_lock() shall protect against interrupts and preemption on the current CPU only. Data shared across CPUs shall be protected by a spinlock acquired with interrupts masked, which on uniprocessor builds shall compile to the critical section alone.
Rationale. Masking is a local operation; pretending otherwise is the classic SMP porting bug (KRN-SMP-004).
Status. Accepted 2026-10-07
Verification. Analysis: SMP specification lock-ordering rules; Test: the spinlock reduces to emb_irq_lock() on UP (symbol inspection).
Trace. SPEC-002 §4.3; KRN-SMP-002, KRN-SMP-004
KRN-IRQ-020 Measured critical-section budgets¶
Statement. Each architecture port shall declare a cycle budget for the kernel’s own critical sections and scheduler locks, and a configuration option shall measure the longest observed durations with the cycle counter. The measured maxima shall be published per reference board with full metadata. Rationale. Evidence, not assertion (principle 6, KRN-RT-007). Status. Accepted 2026-10-07 Verification. Demonstration: benchmark pipeline output per release; Test: checked builds fault when a declared budget is exceeded under the stress suite. Trace. SPEC-002 §10
KRN-IRQ-021 No blocking inside a critical section¶
Statement. A blocking call with a nonzero timeout, a thread-only operation, or a scheduler-lock release that would reschedule, made while a critical section opened by the caller is active, shall be misuse: a kernel fault in checked builds and EMB_EPERM in release builds.
Rationale. A critical section that spans a preemption point leaves interrupts masked for an unbounded time in another thread.
Status. Accepted 2026-10-07
Verification. Test: tests/conformance/misuse/ in both build kinds.
Trace. SPEC-002 §4.2; SPEC-001 §5.3; KRN-RT-002
KRN-IRQ-022 Scheduler lock semantics¶
Statement. emb_sched_lock() and emb_sched_unlock() shall be thread-only, nestable by depth, shall not mask interrupts, and the unlock that reaches depth zero shall perform any pending reschedule immediately. A scheduler-lock operation from interrupt context shall be misuse. Yield while locked shall keep the reschedule pending and shall not switch.
Rationale. Restates KRN-SCH-016 to 019 at the API level and fixes the two edge cases v0.1 left open.
Status. Accepted 2026-10-07
Verification. Test: conformance tests for nesting, ISR wakeup while locked, yield while locked, and the ISR misuse case.
Trace. SPEC-002 §5; KRN-SCH-016, KRN-SCH-017, KRN-SCH-018, KRN-SCH-019
KRN-IRQ-023 Enumerated preemption points¶
Statement. A thread switch shall occur only at: the outermost exit of a kernel-aware interrupt when a reschedule is pending and the scheduler is not locked; inside a thread-context kernel operation that changes schedulability when the caller is not in a critical section and the scheduler is not locked; and kernel start. A thread switch shall never occur inside a nested interrupt or inside a critical section. Rationale. A closed list of preemption points is what makes the kernel’s behavior analyzable and the reference model finite (ADR-013). Status. Accepted 2026-10-07 Verification. Test: differential tests against the reference model’s switch oracle on the native port; Analysis: the kernel has one switch call site per architecture path. Trace. SPEC-002 §6.1; KRN-SCH-021; KRN-IRQ-013
KRN-IRQ-024 Reschedule on outermost exit¶
Statement. When an ISR-safe operation changes the scheduling decision, the kernel shall set the per-CPU reschedule-pending flag and request the architecture’s deferred switch; the architecture’s outermost interrupt exit shall perform the switch when the flag is set and the scheduler is not locked, and shall clear the flag. Rationale. This is the single mechanism by which interrupts drive scheduling (KRN-SCH-020, KRN-IRQ-003). Status. Accepted 2026-10-07 Verification. Test: ISR wakeup latency test on each port; the switch happens exactly once per outermost exit. Trace. SPEC-002 §6.2; KRN-SCH-020
KRN-IRQ-025 Portable handler declaration¶
Statement. The kernel shall provide EMB_ISR(name) as the only portable declaration of a kernel-aware handler, expanding per architecture to the form that provides the kernel’s entry and exit behavior, and EMB_ISR_RAW(name) for handlers that call no kernel function.
Rationale. Cortex-M handlers are plain functions, AVR needs a full-context naked vector, RISC-V needs a dispatcher entry; the application should not know (09 §8).
Status. Accepted 2026-10-07
Verification. Test: the same handler source builds and passes the ISR conformance tests on every port.
Trace. SPEC-002 §6.2, §8.3
KRN-IRQ-026 Bounded nesting¶
Statement. Kernel-aware interrupt nesting shall be enabled only where the architecture permits and the configuration selects it. The maximum depth shall be a configuration constant used to size the interrupt stack, and exceeding it shall be a kernel fault in checked builds. Rationale. Unbounded nesting is unbounded stack use. Status. Accepted 2026-10-07 Verification. Test: nesting-depth test on the native port with fault injection; Analysis: Kconfig gating per architecture. Trace. SPEC-002 §7.1
KRN-IRQ-027 Interrupt stacks¶
Statement. Where the architecture permits, kernel-aware interrupts shall execute on a dedicated per-CPU interrupt stack sized from the maximum nesting depth and the handlers’ measured frames. Where it does not (AVR), every thread’s stack budget shall include a configured interrupt reserve, and the architecture documentation shall state its size derivation.
Rationale. Thread stacks must be sized for thread work only wherever the hardware allows (KRN-MEM-011).
Status. Accepted 2026-10-07
Verification. Analysis: -fstack-usage sums in the stack report; Test: interrupt-stack overflow detection fires in checked builds under the nesting stress test.
Trace. SPEC-002 §7.2; KRN-MEM-011
KRN-IRQ-028 Generic interrupt priority numbering¶
Statement. Generic interrupt priorities shall use the thread convention (a larger number is more urgent), with level 0 the least urgent kernel-aware level and levels above CONFIG_EMB_IRQ_KERNEL_LEVEL kernel-independent. The architecture port shall map generic levels to hardware encodings, and the hardware description shall store generic levels.
Rationale. One priority direction across threads and interrupts removes a documented source of configuration mistakes, and the mapping belongs in one place per architecture.
Status. Accepted 2026-10-07
Verification. Test: emb_irq_set_level() followed by observed preemption order on each port; Analysis: generator emits encoded values from generic input.
Trace. SPEC-002 §8.1
KRN-IRQ-029 Interrupt management API¶
Statement. The kernel shall provide O(1), non-blocking emb_irq_enable, emb_irq_disable, emb_irq_is_enabled, emb_irq_set_level, emb_irq_pend, and emb_irq_clear_pending, and, only when CONFIG_EMB_IRQ_DYNAMIC is selected, emb_irq_connect. By default the vector table shall be generated from the hardware description and static.
Rationale. A static table costs no RAM and no init code; dynamic connection is an option for the applications that need it.
Status. Accepted 2026-10-07
Verification. Test: API conformance per port; Analysis: no RAM vector table in the tiny profile image.
Trace. SPEC-002 §8.2; HW-001
KRN-IRQ-030 Exceptions route to the fault manager¶
Statement. Synchronous faults shall enter through the architecture fault entry, which shall capture the available context and dispatch to the fault manager, classifying a fault from an unprivileged partition as a partition fault and any other as a kernel fault. System-call traps shall not be treated as faults. The crash record shall be written before any recovery action. Rationale. Fault handling that is designed, not improvised (01 §6); isolation requires the partition classification. Status. Accepted 2026-10-07 Verification. Test: provoked faults of each class on native and Cortex-M (emulated) produce decodable crash records and the right classification. Trace. SPEC-002 §9; 03 §10; FLT-001, FLT-002
KRN-IRQ-031 Timer interrupt level and bound¶
Statement. The system timer interrupt shall be a kernel-aware interrupt whose level defaults to the highest kernel-aware level and is configurable, and whose handler shall be bounded to moving expired timeouts to READY, setting the reschedule flag, and programming the next event.
Rationale. Timeout jitter should depend on critical sections and zero-latency interrupts only, and the handler must not become a place where work accumulates.
Status. Accepted 2026-10-07
Verification. Demonstration: timer jitter benchmark; Analysis: handler -fstack-usage and cycle budget.
Trace. SPEC-002 §11; KRN-TIM-006
KRN-IRQ-032 Latency metrics are defined and published¶
Statement. The project shall define interrupt latency, kernel masking latency, ISR overhead, ISR-to-thread latency, and scheduler-lock latency as in SPEC-002 §10.1, shall measure them on every reference board with the benchmark pipeline, and shall publish worst observed values with full metadata. Rationale. KRN-RT-004 to 007 require measurability; this fixes what is measured. Status. Accepted 2026-10-07 Verification. Demonstration: published benchmark data per release. Trace. SPEC-002 §10; KRN-RT-004, KRN-RT-005, KRN-RT-006, KRN-RT-007; TEST-006
KRN-IRQ-033 The kernel never unmasks behind a caller¶
Statement. An ISR-safe kernel operation called while the caller holds a critical section shall return with the caller’s mask state unchanged; kernel internals shall save and restore mask state with the same key-based primitive and shall never unconditionally enable interrupts.
Rationale. A kernel that enables interrupts inside a caller’s critical section breaks the caller’s invariant silently.
Status. Accepted 2026-10-07
Verification. Test: every ISR-safe function called under emb_irq_lock(); the key read after the call equals the key before; Analysis: no unconditional enable instruction in kernel/ or in the ports’ kernel paths.
Trace. SPEC-002 §4.2
KRN-IRQ-034 Context query is O(1) and exact¶
Statement. emb_context() shall be O(1), callable from any context including nested interrupts and pre-kernel, and shall agree with the hardware’s notion of exception activity on architectures that expose one.
Rationale. It is executed on every checked API entry and must be cheap and right.
Status. Accepted 2026-10-07
Verification. Test: context query inside nested interrupts and before kernel start on every port.
Trace. SPEC-002 §2.1; KRN-IRQ-002
KRN-IRQ-035 Checked-build detection¶
Statement. Checked builds shall detect and raise a kernel fault for: out-of-order emb_irq_unlock(), scheduler-lock operations from interrupt context, nesting beyond the configured maximum, interrupt stack overflow, and kernel calls from EMB_ISR_RAW handlers on architectures where context can be distinguished.
Rationale. These bugs are invisible in release builds until they corrupt state.
Status. Accepted 2026-10-07
Verification. Test: tests/conformance/misuse/irq/ provokes each condition on the native port and on an emulated Cortex-M.
Trace. SPEC-002 §12; API-015
KRN-IRQ-036 Handoff from kernel-independent interrupts¶
Statement. The architecture port shall provide emb_arch_irq_pend_soft(), callable from a kernel-independent handler, that pends a kernel-aware software interrupt whose handler may perform kernel work on behalf of the kernel-independent handler. Documentation shall present this as the only sanctioned path from a kernel-independent handler to the kernel.
Rationale. Zero-latency handlers need a way to wake threads without touching kernel state.
Status. Accepted 2026-10-07
Verification. Test: on Cortex-M with the class enabled, a kernel-independent handler pends the software interrupt and a thread is woken with measured latency.
Trace. SPEC-002 §3.2