Skip to content

feat(arch,container): ISR safety abstraction and interrupt-safe ringbuf APIs (#105) - #112

Merged
gg582 merged 1 commit into
mainfrom
feat/isr-safe-primitives
Oct 29, 2026
Merged

gg582 merged 1 commit into
mainfrom
feat/isr-safe-primitives

Conversation

@gg582

@gg582 gg582 commented Oct 29, 2026

Copy link
Copy Markdown
Member

Closes #105.

What

<ttak/arch/ttak_critical.h> — task-context and ISR-context critical sections:

  • TTAK_ENTER_CRITICAL() / TTAK_EXIT_CRITICAL() — Cortex-M: cpsid i / cpsie i; FreeRTOS: taskENTER_CRITICAL() / taskEXIT_CRITICAL(); hosted POSIX / MSVC x86: documented no-ops.
  • TTAK_ENTER_CRITICAL_ISR(state) / TTAK_EXIT_CRITICAL_ISR(state) — Cortex-M: PRIMASK save/restore; FreeRTOS: taskENTER_CRITICAL_FROM_ISR() / taskEXIT_CRITICAL_FROM_ISR(). The state argument (a ttak_critical_state_t declared by the caller) carries the interrupt mask between enter/exit — required for correct nesting and for the FreeRTOS BASEPRI-based FromISR API.

Ring buffer _isr variants — ttak_ringbuf_push_isr() / ttak_ringbuf_pop_isr():

  • Never take the pthread rwlock (illegal in ISR context) and instead serialize with the ISR critical section, so an ISR can never deadlock against a task holding the rwlock.
  • Existing task-context APIs are untouched (refactored onto shared unlocked helpers).
  • Documented constraint: when a buffer is shared between a task and an ISR, both sides must use the _isr variants; the regular APIs must not be mixed with them on the same buffer.

Tests

  • tests/test_ringbuf_isr.c:
    • Host: smoke test of the _isr API surface and ordering (critical sections are no-ops there, per documentation).
    • QEMU Cortex-M (bare-metal and FreeRTOS jobs): enables and pends NVIC IRQ0 — new weak TTAK_IRQ0..IRQ3_Handler slots added to the harness vector table in tests/baremetal/startup_cortex_m.c — which pushes a burst of payloads from the real ISR while the task pops with ttak_ringbuf_pop_isr(), asserting in-order delivery with no loss across buffer wrap-around (200 items through a 16-slot buffer).
  • Registered in BAREMETAL_TESTS, so it runs in the existing qemu-tests and freertos-qemu-tests CI jobs with no runner changes.

Docs

README "ISR safety and critical sections" section under Microcontrollers (Bare Metal).

Verified locally

  • make test — full host suite passes.
  • make PLATFORM=baremetal BOARD=mps2_an500 test image builds for the new test (and lib builds for cortex-m0plus/m3-class flags: -mcpu=cortex-m0plus -mthumb -mfloat-abi=soft and cortex-m4f).
  • make PLATFORM=freertos ... baremetal-tests — all 39 images build against FreeRTOS V11.1.0.
  • check_stack_usage.py --core cortex-m7 passes (new _isr frames are 8 B, same as the task variants).

Deferred to CI

  • QEMU execution on mps2-an500 (bare-metal + FreeRTOS): qemu-system-arm is not installed locally and could not be installed; the images build and the test follows the existing harness conventions exactly.

#105)

Add <ttak/arch/ttak_critical.h> with task-context and ISR-context
critical-section macros:

- TTAK_ENTER_CRITICAL()/TTAK_EXIT_CRITICAL(): cpsid i/cpsie i on
  Cortex-M, taskENTER/EXIT_CRITICAL() on FreeRTOS, documented no-ops on
  hosted POSIX and MSVC/x86.
- TTAK_ENTER_CRITICAL_ISR(state)/TTAK_EXIT_CRITICAL_ISR(state): PRIMASK
  save/restore on Cortex-M, taskENTER/EXIT_CRITICAL_FROM_ISR() on
  FreeRTOS (the state argument carries the interrupt mask, which the
  FreeRTOS FromISR API requires).

Add ttak_ringbuf_push_isr()/ttak_ringbuf_pop_isr(): they never take the
pthread rwlock (illegal in ISR) and serialize with the ISR critical
section instead, so an ISR can never deadlock against a task holding the
lock. When a buffer is shared between a task and an ISR, both sides must
use the _isr variants; the regular task-context APIs stay unchanged.

Tests:
- tests/test_ringbuf_isr.c: host smoke test of the _isr API surface
  (no-op critical sections), plus a Cortex-M producer/consumer test that
  pends NVIC IRQ0 (new weak TTAK_IRQ0..3 slots in the startup vector
  table) which pushes payloads from the ISR while the task pops and
  asserts order and no loss, on both bare-metal and FreeRTOS builds.
- Registered in BAREMETAL_TESTS so it runs in the QEMU mps2-an500
  bare-metal and FreeRTOS CI jobs.

Documented the macros and the task/ISR mixing rule in README.
@gg582
gg582 force-pushed the feat/isr-safe-primitives branch from 3a4af42 to 6f57e33 Compare October 29, 2026 12:07
@gg582
gg582 merged commit f3f65c8 into main Oct 29, 2026
11 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(arch): ISR safety abstraction and interrupt-safe queue primitives

1 participant