Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 34 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# AVR with avr-gcc run under QEMU and on EmbSIM's Arduino Uno, the Cortex-M4F suite on EmbSIM's
# NUCLEO-F446RE (SIM-002), formatting, and the footprint gate (TEST-011).
# Target order: Cortex-M and RISC-V first, AVR secondary (ADR-038).
# The EmbCC legs join when the compiler is available to CI (09 §11).
# The experimental EmbCC-kernel / GCC-host native legs use a pinned EmbCC release (09 §11).
name: ci

on:
Expand Down Expand Up @@ -371,10 +371,42 @@ jobs:
path: case-evidence-rv32-c3-embsim.json
if-no-files-found: warn

# The experimental EmbCC-kernel / GCC-host native build (ADR-041), with the compiler pinned
# to a release and its digest (docs/engineering/embcc-native-linux.md).
embcc:
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
preset: [native-embcc, native-embcc-release, native-embcc-tiny, native-embcc-periodic]
env:
EMBCC_VERSION: 0.0.1-beta
EMBCC_SHA256: 984b25acf1b93d61416887530c9589be96b43437a8de8d61ffd07cf6a856551a
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install tools
run: |
sudo apt-get update
sudo apt-get install -y ninja-build python3-yaml
- name: Install EmbCC
run: |
archive="embcc-${EMBCC_VERSION}-linux-x86_64.tar.gz"
curl -fsSL -o "$archive" "https://github.com/EmbLinkOs/EmbCC/releases/download/v${EMBCC_VERSION}/${archive}"
echo "${EMBCC_SHA256} ${archive}" | sha256sum -c -
mkdir -p "$HOME/embcc"
tar -xzf "$archive" -C "$HOME/embcc" --strip-components=1
"$HOME/embcc/bin/embcc" --version
- name: Configure
run: cmake --preset ${{ matrix.preset }} -DEMB_KERNEL_COMPILER="$HOME/embcc/bin/embcc"
- name: Build
run: cmake --build --preset ${{ matrix.preset }}
- name: Test
run: ctest --preset ${{ matrix.preset }} --output-on-failure --no-tests=error

merge_gate:
name: CI merge gate
if: ${{ always() }}
needs: [native, cortex_m, riscv, avr, avr-embsim, cm4-embsim, rv32-embsim, lint]
needs: [native, cortex_m, riscv, avr, avr-embsim, cm4-embsim, rv32-embsim, embcc, lint]
runs-on: ubuntu-24.04
steps:
- name: Require every matrix and lint job to succeed
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ User-visible changes are recorded here. There are no released versions or releas

### Added

- A CI job runs the experimental EmbCC-kernel / GCC-host native presets (`native-embcc`, `-release`, `-tiny`, `-periodic`) with the EmbCC `0.0.1-beta` release, pinned by version and SHA-256; the merge gate requires it.

- Work-queue statistics (`CONFIG_EMB_WORKQ_STATS`, off by default; KRN-WQ-011, A65): `emb_workq_get_stats()` reports the worst submit-to-start latency, the longest handler with its function and the deepest backlog per queue, in ticks; `emb_workq_reset_stats()` restarts them.

- Static definitions for the other object types (A64): `EMB_SEM_DEFINE`, `EMB_MUTEX_DEFINE`, `EMB_EVENT_DEFINE`, `EMB_COND_DEFINE`, `EMB_MSGQ_DEFINE`, `EMB_WORKQ_DEFINE` and, for interrupt-context callbacks, `EMB_TIMER_DEFINE` declare storage (with the ring or stack) and the handle and construct the object in `emb_kernel_init()`.

- Round-robin time slicing (`CONFIG_EMB_TIME_SLICING`, off by default): a thread at or below `CONFIG_EMB_TIMESLICE_PRIORITY` that runs for `CONFIG_EMB_TIMESLICE_TICKS` without blocking moves behind its READY equal-priority peers; without a peer its quantum is renewed (KRN-SCH-007, 026, 037; A63). The quantum is a deadline in the tickless computation and a comparison in the periodic tick. The reference model implements it, the new `native-timeslice` preset checks it through the differential bridge, and `native-timeslice-tickless` runs the conformance cases with the tickless clock. List scheduler only.
Expand Down
2 changes: 2 additions & 0 deletions configs/native-timeslice.conf
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
CONFIG_EMB_TIME_SLICING=y
CONFIG_EMB_TIMESLICE_TICKS=2
CONFIG_EMB_TIMESLICE_PRIORITY=20
# Work-queue statistics (KRN-WQ-011), also off by default, are built and tested here too.
CONFIG_EMB_WORKQ_STATS=y
# Periodic clock: the quantum then counts delivered ticks exactly, as the model does. In
# tickless builds it starts from the free-running counter, which the model cannot see.
# CONFIG_EMB_TICKLESS is not set
6 changes: 3 additions & 3 deletions docs/STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ This page is the authoritative inventory of implementation and available evidenc
| Synchronization | Semaphores, mutexes with inheritance, ceiling, recursion and owner-death policy; event flags with ANY/ALL/CLEAR waits and binding (M2-05); condition variables with the mandatory relock (M2-06) | Conformance and native differential bridge; inheritance and deadlock detection have a configured depth limit |
| Communication | Copy-by-value message queues: direct hand-off to a waiting receiver, slot hand-off from a waiting sender, send to front, peek, `EMB_NO_WAIT` calls from ISRs and a receive-side binding (M2-07) | Conformance and native differential bridge; no pipes, buffer pools or zero-copy ownership queues; the masked copy time is bounded by configuration, not measured on hardware |
| Software timers | One-shot and drift-free periodic timers in their own deadline list (ADR-047), with callbacks on a work queue or in interrupt context, closed-form catch-up and overrun counts, stop states and `stop_sync` (M2-09) | Conformance and native differential bridge; list scheduler only (not tiny); arming overhead and jitter not measured on hardware |
| Deferred work | Work queues on a kernel thread with FIFO execution, idempotent and ISR-safe submit, resubmission while running, cancel and synchronous cancel, flush, destroy joining the thread, a system queue linked only when referenced (M2-08, ADR-048), and delayed work items over internal timers (M2-09) | Conformance and native differential bridge; list scheduler only (not tiny); no statistics |
| Deferred work | Work queues on a kernel thread with FIFO execution, idempotent and ISR-safe submit, resubmission while running, cancel and synchronous cancel, flush, destroy joining the thread, a system queue linked only when referenced (M2-08, ADR-048), and delayed work items over internal timers (M2-09) | Conformance and native differential bridge; list scheduler only (not tiny); optional per-queue statistics (A65), conformance-tested on native and spot-checked on QEMU Cortex-M4 |
| Notifications | Per-thread bits; bindings from semaphores, event flags and message queues to a thread, with unbind; a bound thread cannot be destroyed (ADR-046) | Binding takes a one-bit mask; pipes and pools do not exist to bind; restart generations need the isolated profile |
| Objects | Caller-owned generated storage and POINTER handles; per-type active-object lists for every handle object type (`CONFIG_EMB_OBJ_LIST`) used by init to refuse live storage (ADR-045) | No INDEXED or TABLE handles, capability rights, partition restart, system freeze, `emb_obj_foreach()` or debug-descriptor export |
| Native port | POSIX host-thread gate, deterministic IRQ injection, virtual time | Base/tiny development workflow; no current wall-clock, asynchronous signal stress, simulated isolated profile or Win32 backend |
| Embedded ports | ATmega328P; Cortex-M3/M4F; RV32IMAC and RV32IMC machine mode; boards Arduino Uno, NUCLEO-F446RE, ESP32-C3-DevKitM-1, QEMU's MPS2 and RV32 virt | QEMU jobs and EmbSIM jobs (Uno, NUCLEO-F446RE, ESP32-C3-DevKitM-1) defined in CI; no real-board timing or peripheral/HIL validation recorded here |
| Configuration/build | Kconfig subset, port manifests, CMake/Ninja, layout probe, footprint tool | GCC/Clang native CI and cross-GCC QEMU jobs; ten legacy EmbCC capabilities reviewed with scoped local checks, but current RTOS compiler CI/qualification remains incomplete |
| Configuration/build | Kconfig subset, port manifests, CMake/Ninja, layout probe, footprint tool | GCC/Clang native CI and cross-GCC QEMU jobs; an EmbCC-kernel/GCC-host native CI leg on a pinned release; ten legacy EmbCC capabilities reviewed with scoped local checks, but embedded EmbCC builds and compiler qualification remain incomplete |
| Observability | M1 trace sink and fault reporting; trace records for every outcome of the M2 waits and for queue, work and timer events (IDs 31 to 44) | CTF rings/metadata, deferred log decoder, retained crash records, debug descriptor and worst-case monitors remain planned |
| Documentation | Sphinx/MyST manuals and native tutorials, Doxygen/Breathe C API, Sphinx Needs design catalog, JSON/CSV downloads and annotation audit | Strict local HTML build, complete extracted function annotations, source-preservation and catalog-integrity checks; merged `37887c9` Pages deployment and served evidence-workflow page independently observed successful |
| Repository process | Issue forms, PR checklist, changelog, release/M2 work checklists, stable CI merge checks, authored-commit DCO checker and a main ruleset policy | Local syntax and DCO/gate failure checks; GitHub's effective main rules report PRs, resolved conversations, the three strict CI checks and deletion/non-fast-forward protection; no remote rejection experiment claimed |
Expand Down Expand Up @@ -66,7 +66,7 @@ The user-guide pass also configured native/base with stack statistics and two TL

## Known limits and unresolved evidence

The [EmbCC layout-marker correction](engineering/embcc-layout-marker.md), source `3578006`, supplies the portability macro; storage/assertion/kernel-archive compilation passed on eight configurations. The subsequent [Linux native integration](engineering/embcc-native-linux.md), source `df32ec2`, adds explicit experimental EmbCC-kernel/GCC-host presets and a build-time layout guard. Actual checked/release/tiny/periodic mixed builds passed all twelve CTest targets each and 11,200 seeded model comparisons in total, with zero divergences. GCC compiles the POSIX port, board, applications and harness and links the real Linux runtime; this is not an all-EmbCC host build. The latter still fails on glibc header compatibility after an explicit system-header/link experiment. Compiler CI currently checks the marker/launcher contracts and the existing matrix; the EmbCC executions are scoped local evidence.
The [EmbCC layout-marker correction](engineering/embcc-layout-marker.md), source `3578006`, supplies the portability macro; storage/assertion/kernel-archive compilation passed on eight configurations. The subsequent [Linux native integration](engineering/embcc-native-linux.md), source `df32ec2`, adds explicit experimental EmbCC-kernel/GCC-host presets and a build-time layout guard. Actual checked/release/tiny/periodic mixed builds passed all twelve CTest targets each and 11,200 seeded model comparisons in total, with zero divergences. GCC compiles the POSIX port, board, applications and harness and links the real Linux runtime; this is not an all-EmbCC host build. The latter still fails on glibc header compatibility after an explicit system-header/link experiment. CI now runs the four mixed presets with the pinned EmbCC `0.0.1-beta` release on every pull request (merge-gated; 20, 20, 20 and 17 CTest targets passed on the first run); deeper campaigns remain scoped local evidence.

- Hardware timing and total memory use remain to be demonstrated on the primary Cortex-M board. Map-derived kernel subtotals exclude port, board, runtime and stack costs.
- The Cortex-M base TCB figures in the port page exceed R-003 T4's target; that is a disclosed target miss, not a failed native setup.
Expand Down
6 changes: 5 additions & 1 deletion docs/engineering/embcc-native-linux.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ python3 -I tools/model/bridge.py \

The [evidence archive](https://github.com/EmbLinkOs/EmbLinkRTOS/tree/main/tools/toolchain/evidence/embcc-native-2026-10-15) retains actual compile commands, resolved configurations, layouts, runner/source/toolchain identities, raw and readable logs, and initial POSIX/negative-check inputs. Its manifest records hashes and commands. Readable logs strip trailing whitespace; `raw-logs.json` retains original output. Compiler warnings for unsupported diagnostic options remain visible; no warning suppression was added.

## CI leg

Since 2026-10-31 the `embcc` CI job runs the four presets on every pull request and push to main, and the merge gate requires it. It installs the EmbCC `0.0.1-beta` Linux x86-64 release archive, checked against a SHA-256 pinned in `.github/workflows/ci.yml`, and passes its `embcc` as `EMB_KERNEL_COMPILER`. On the first run ([PR #45](https://github.com/EmbLinkOs/EmbLinkRTOS/pull/45)) the checked, release and periodic presets passed 20 of 20 CTest targets each and tiny 17 of 17, including the differential bridge at CTest depth (6 runs per scenario, seed 1). The release is a newer compiler than the source revision measured above; updating it means changing the version and the digest together.

## Remaining scope

CI runs the launcher/storage contracts and existing GCC/Clang/embedded matrix. The actual EmbCC executions above are local evidence, not a pinned EmbCC CI leg. Other hosts, compiler revisions, PIE/LTO, sanitizing the EmbCC kernel, embedded images and physical timing remain unqualified. AVR flash/registration integration, RTOS hardware-import adaptation, embedded C++ checks and complete compiler/port conformance remain separate tasks. A subsequent all-EmbCC host build must resolve the actual POSIX header/runtime/link boundaries rather than inheriting the mixed build's result.
CI runs the launcher/storage contracts, the existing GCC/Clang/embedded matrix and the pinned EmbCC-kernel leg. Deeper campaigns with the EmbCC kernel remain the local evidence above. Other hosts, compiler revisions, PIE/LTO, sanitizing the EmbCC kernel, embedded images and physical timing remain unqualified. AVR flash/registration integration, RTOS hardware-import adaptation, embedded C++ checks and complete compiler/port conformance remain separate tasks. A subsequent all-EmbCC host build must resolve the actual POSIX header/runtime/link boundaries rather than inheriting the mixed build's result.
4 changes: 2 additions & 2 deletions docs/requirements/KRN-WQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,6 @@ KRN-WQ-001 to 004 originate in `docs/architecture/03-kernel-architecture.md` §6
### KRN-WQ-011 Trace and statistics
**Statement.** Submit, start with submit-to-start latency, end with duration, cancel, and delayed scheduling shall be trace events; maximum FIFO length, worst latency, and longest handler with its address shall be optional statistics per queue.
**Rationale.** Work queue latency is the latency of every timer callback and bottom half.
**Status.** Accepted 2026-10-07; trace records implemented (A52); statistics are not.
**Verification.** Test: trace decoder (not written); statistics API test (no API).
**Status.** Accepted 2026-10-07; trace records implemented (A52); statistics implemented with `CONFIG_EMB_WORKQ_STATS` (A65).
**Verification.** Test: `workq_stats_record_depth_latency_and_longest_handler` on `native-timeslice`; trace decoder (not written).
**Trace.** SPEC-006 §7; OBS-005
1 change: 1 addition & 0 deletions docs/specs/AMENDMENTS-M2.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@ Corrections found while preparing the M2 primitives, where an accepted specifica
| A62 | KRN-SCH-036, 03 §2.1 | The priority count's lower bound is 2, as `CONFIG_EMB_PRIORITY_COUNT` has always allowed, not 4: idle plus one application level is a valid tiny configuration. Accepted by the project owner 2026-10-31. | `kernel/Kconfig` |
| A63 | SPEC-003 §8, KRN-SCH-007, KRN-SCH-026, KRN-SCH-037, KRN-SCH-041, KRN-TIM-029 | Time slicing is implemented with one quantum (`CONFIG_EMB_TIMESLICE_TICKS`) and one threshold (`CONFIG_EMB_TIMESLICE_PRIORITY`, 255 for every level). It requires the list scheduler: `CONFIG_EMB_TIME_SLICING` depends on `!CONFIG_EMB_SCHED_TABLE`, since a table level holds one thread. The quantum restarts at every dispatch, also for a preempted thread resuming ahead of its peers, and a yield without a peer keeps it running. Expiry renews the quantum and, with a READY peer, sets a per-CPU rotation flag that makes the next decision place the thread behind its peers. A thread raised above the threshold stops being sliced at its next expiry; one lowered below it starts at its next dispatch. The reference model implements the same rules; the differential bridge checks them with the periodic clock only (`native-timeslice`), because a tickless quantum starts from the free-running counter, which can run ahead of the ticks the model counts. Implemented 2026-10-31 at the project owner's request; the details await review. | `kernel/time/time.c`, `kernel/sched/sched.c`, `kernel/Kconfig` |
| A64 | SPEC-001 §6.4, SPEC-009 §5.2, API-021, A40 | The deferred cross-type `_DEFINE` change: `EMB_SEM_DEFINE(sym, initial, max)`, `EMB_MUTEX_DEFINE(sym, protocol, ceiling, flags)`, `EMB_EVENT_DEFINE(sym, initial, flags)`, `EMB_COND_DEFINE(sym, flags)`, `EMB_MSGQ_DEFINE(sym, item_size, capacity, flags)` with its ring, and `EMB_WORKQ_DEFINE(sym, priority, stack_size)` with its stack. They take positional fields like `EMB_THREAD_DEFINE` rather than an attribute initializer, because a partial initializer would zero fields whose defaults are not zero (a semaphore's `max`, a work queue's priority). The table entry stays one init-wrapper pointer, as for threads, not `{init_fn, &storage, &attr, &handle}`. `EMB_TIMER_DEFINE(sym, fn, arg)` defines interrupt-context timers only: a work-queue timer needs its queue at construction and table entries, the system queue's included, run in link order, while `EMB_INIT_AFTER` is not implemented. The object name is the symbol where `CONFIG_EMB_OBJ_NAMES` keeps names, else none. A construction failure faults through `emb_check_status()`. | `include/emb/*.h` |
| A65 | SPEC-006 §7, KRN-WQ-011, A52 | Work-queue statistics are `CONFIG_EMB_WORKQ_STATS` (off by default): `emb_workq_get_stats()` fills `emb_workq_stats_t` (worst submit-to-start latency, longest handler and its function, items queued now and at most), and `emb_workq_reset_stats()` restarts the maxima, the pending maximum from the items queued now. Both are `thread isr` and O(1). Times are kernel-clock ticks, not cycles, so a handler shorter than a tick reads as 0. A submit while the item's handler runs starts the latency of the run it queues, and flush markers are not items. Each work item gains a submit timestamp. The per-thread count of notification sets is not implemented. | `kernel/work/workq.c`, `include/emb/work.h` |
2 changes: 1 addition & 1 deletion docs/specs/SPEC-006-notifications-and-work-queues.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ Handler latency is the sum of the queue thread's dispatch latency at its priorit

## 7. Observability

Trace events: `notify_set(target, bits, woke)`, `notify_wait(thread, mask, mode, result)`, `bind_signal(object, thread, bit)`, `work_submit(queue, item, result)`, `work_start(queue, item, latency)`, `work_end(queue, item, duration)`, `work_cancel(item, state)`, `dwork_schedule(item, deadline)`. Statistics (optional): per queue, maximum FIFO length, worst submit-to-start latency, longest handler with its address; per thread, notification sets received. The debug descriptor (ADR-011) exports the work item layout so a debugger can list a queue's pending items.
Trace events: `notify_set(target, bits, woke)`, `notify_wait(thread, mask, mode, result)`, `bind_signal(object, thread, bit)`, `work_submit(queue, item, result)`, `work_start(queue, item, latency)`, `work_end(queue, item, duration)`, `work_cancel(item, state)`, `dwork_schedule(item, deadline)`. Statistics (optional): per queue, maximum FIFO length, worst submit-to-start latency, longest handler with its address, read with `emb_workq_get_stats()` and restarted with `emb_workq_reset_stats()` under `CONFIG_EMB_WORKQ_STATS` (A65); per thread, notification sets received (not implemented). The debug descriptor (ADR-011) exports the work item layout so a debugger can list a queue's pending items.

## 8. Tiny profile

Expand Down
Loading