<feed xmlns='http://www.w3.org/2005/Atom'>
<title>threadx.git/test/smp/regression, branch v6.4.1_cert</title>
<subtitle>Unnamed repository; edit this file 'description' to name the repository.</subtitle>
<id>http://cgit.235523.xyz/threadx.git/atom/test/smp/regression?h=v6.4.1_cert</id>
<link rel='self' href='http://cgit.235523.xyz/threadx.git/atom/test/smp/regression?h=v6.4.1_cert'/>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/threadx.git/'/>
<updated>2026-09-21T04:01:02Z</updated>
<entry>
<title>Covered the user event insert's own test of a disabled trace buffer</title>
<updated>2026-09-21T04:01:02Z</updated>
<author>
<name>Frédéric Desbiens</name>
<email>frederic.desbiens@eclipse-foundation.org</email>
</author>
<published>2026-09-21T04:01:02Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/threadx.git/commit/?id=ac514bcc246e4b57c05f5e1bf071d2bcf23be1da'/>
<id>urn:sha1:ac514bcc246e4b57c05f5e1bf071d2bcf23be1da</id>
<content type='text'>
_tx_trace_user_event_insert tests the trace buffer pointer and returns
TX_NOT_DONE if it is null; the insert sits in the else, and the macro reads the
same variable and tests it again a few instructions later, inside one
protection with nothing between. The second test's false arm had no route on one
core and was carried as unreachable.

It is an ordinary state of the running kernel on SMP, and no fault has to be
invented for it. _tx_trace_disable clears that pointer and takes no lock of any
kind, so a thread disabling tracing on one core while another is inside the
insert clears it under that core. A new test drives 300,000 inserts against a
second thread on a core of its own writing the same store the disable service
writes. No kernel symbol is replaced and both services run their own code from
end to end; the test asserts that the two threads held different cores and that
the writer's stores reached the service, and says in the file that the arm
itself is evidenced by the coverage report because nothing outside the macro can
observe it.

The pass count is sized from measurement on the slower of two machines. The arm
is taken 49 to 132 times per run on this workstation over three runs and 521 to
1298 times per run on a CI runner over seven.

136/136 in each of eight configurations, twice from clean, 3588/3612 branch
outcomes on the union basis against 3587/3612 before. Fifty standalone repeats
in each of the eight, no failures.

Assisted-by: Claude Code (Opus 5) &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Covered the second MISRA loop the always-true shim controls</title>
<updated>2026-09-21T00:09:11Z</updated>
<author>
<name>Frédéric Desbiens</name>
<email>frederic.desbiens@eclipse-foundation.org</email>
</author>
<published>2026-09-21T00:09:11Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/threadx.git/commit/?id=a8c6845eda7168f02a2bde64b010c231b56fc77c'/>
<id>urn:sha1:a8c6845eda7168f02a2bde64b010c231b56fc77c</id>
<content type='text'>
TX_LOOP_FOREVER appears twice in common_smp/src. Under TX_MISRA_ENABLE both
expand to a call on _tx_misra_always_true rather than to a literal, so each
carries an exit arm the kernel never takes. The timer thread's loop was already
covered by replacing that shim; the per-core state initialisation loop in
_tx_thread_smp_current_state_set was not, because the kernel reaches it only
from the three initialisation paths that run before the scheduler starts a
thread.

The existing test drives it directly instead, with the shim already armed and
the timer thread already ended, so nothing else in the run can reach the shim
while it is refusing. The service is handed back the state its highest core
already holds, so the one assignment a shortened loop performs writes the value
that was there; the test asserts afterwards that every core's state is the one
it saw before the call, and that the shim refused exactly twice. No second
symbol is replaced and no test is added to the list of those that replace one.

2/2 at tx_thread_smp_current_state_set.c:97, seven executions of the loop and
one exit, measured with the coverage isolated to this test. 135/135 in each of
eight configurations and 3587/3612 branch outcomes on the union basis. Fifty
standalone repeats in each of the eight, no failures.

Assisted-by: Claude Code (Opus 5) &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Covered the byte allocate's overwritten trace entry</title>
<updated>2026-09-21T00:08:56Z</updated>
<author>
<name>Frédéric Desbiens</name>
<email>frederic.desbiens@eclipse-foundation.org</email>
</author>
<published>2026-09-21T00:08:56Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/threadx.git/commit/?id=194d128bec585d6535ff9ac37bd0ac35b8f9cafc'/>
<id>urn:sha1:194d128bec585d6535ff9ac37bd0ac35b8f9cafc</id>
<content type='text'>
The byte allocate records a trace event on the way in, saves the entry's time
stamp, and comes back to write the address it returned into that same entry --
but only if the time stamp says nothing overwrote the entry meanwhile. Nothing
in the kernel writes a trace event inside the window, so the other arm had no
agent and no test.

The Linux SMP port's TX_BYTE_ALLOCATE_EXTENSION gains a second clause, guarded
by its own flag and calling a routine the harness declares weakly, in the shape
TX_BYTE_RELEASE_EXTENSION already uses. The hook runs between the restore and
the disable that bracket the pool search, which on SMP is a real release of the
protection rather than an interrupt gap. A new test filters the byte pool event
class so the allocate's own insert writes nothing and leaves the buffer parked
on the saved entry, then lets the hook write a user event onto it; neither lever
reaches the arm without the other. No kernel symbol is replaced and the allocate
runs its own code end to end. The macro expands inside tx_byte_allocate.c, so
the new clause's if is certified-source branch: the union branch denominator
moves from 3610 to 3612 and both new outcomes are covered.

The arm closes in trace_build alone. Under TX_MISRA_ENABLE the port's trace time
source returns a constant, so the comparison reads 0 == 0 whatever the hook
writes, and the test asserts the consequence only where the time source is real.

135/135 in each of eight configurations, 3586/3612 branch outcomes on the union
basis against 3583/3610 before. Fifty standalone repeats in each of the eight,
no failures.

Assisted-by: Claude Code (Opus 5) &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Covered the enable's inserts with their own event class filtered</title>
<updated>2026-09-20T22:16:05Z</updated>
<author>
<name>Frédéric Desbiens</name>
<email>frederic.desbiens@eclipse-foundation.org</email>
</author>
<published>2026-09-20T22:16:05Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/threadx.git/commit/?id=ed6c279090c3ece241a82725389c32ecfb224f08'/>
<id>urn:sha1:ed6c279090c3ece241a82725389c32ecfb224f08</id>
<content type='text'>
The two inserts the trace enable writes read an event class the same call sets
to all ones a few hundred lines above them, so from inside the enabling thread
neither can find it disabled. A buffer-full notification reaches the second one,
because it is called from inside the first; the first has no lever of that kind
and sat at 10 of 12.

SMP has one the monoprocessor does not, and it is an arrangement rather than a
race because the enable blocks. tx_trace_event_filter is an unprotected
read-modify-write of the enable bits, while the enable takes the SMP protection
after setting them and long before either insert, so a thread already holding
the protection on another core parks the enable there for as long as it likes. A
new test takes the protection from a core of its own, waits for the bits, clears
every class and releases; the enable runs on and both inserts find the class
gone. It asserts the consequence rather than the timing - neither insert wrote
an entry, so the buffer is where the enable left it.

A first version that waited for the window instead of holding it open was
measured and discarded: it failed 11 runs of 400, and widening the window
eightfold only took that to 3 of 100. tx_trace_enable.c:391 goes to 11 of 12 and
:392 stays at 12. 133/133 in each of the eight configurations, and 50 standalone
repeats of the new test green in every one of them.

Assisted-by: Claude Code (Opus 5) &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Covered the three registry decisions ordinary use never reaches</title>
<updated>2026-09-20T21:55:38Z</updated>
<author>
<name>Frédéric Desbiens</name>
<email>frederic.desbiens@eclipse-foundation.org</email>
</author>
<published>2026-09-20T21:55:38Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/threadx.git/commit/?id=2f09a736f94d44623eae10b87cb7fefb9c3027b7'/>
<id>urn:sha1:2f09a736f94d44623eae10b87cb7fefb9c3027b7</id>
<content type='text'>
The trace object registry carried one uncovered line and three uncovered branch
outcomes. The name copy stops at the string's terminator, so it never left the
loop by its own count and never met a caller passing no name at all. The search
that reuses an entry prefers a later free one unless the earlier one has never
held a valid object, and nothing the kernel registers produces an entry that is
both in use and of no valid type.

A new test registers an object whose name is longer than a registry entry keeps
room for, one with no name, and one of the type the registry treats as not
valid. It then fills the registry, frees the not-valid entry last so the search
starts there, registers again, and asserts the new object landed in the entry
the search kept rather than in the later free one. The registry is rearranged
under one SMP protection, because every service that creates an object writes
it.

tx_trace_object_register.c goes to 66/66 lines and 42/42 branch outcomes on the
union of the eight configurations, from 65/66 and 39/42. 133/133 in each of the
eight, and 50 standalone repeats of the new test green in every one of them.

Assisted-by: Claude Code (Opus 5) &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Covered both trace inserts the enable service writes itself</title>
<updated>2026-09-20T21:55:38Z</updated>
<author>
<name>Frédéric Desbiens</name>
<email>frederic.desbiens@eclipse-foundation.org</email>
</author>
<published>2026-09-20T21:55:38Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/threadx.git/commit/?id=90707029524ff145397035ae4d9d78eec0674260'/>
<id>urn:sha1:90707029524ff145397035ae4d9d78eec0674260</id>
<content type='text'>
The enable records two running events so that a buffer handed to an analysis
tool is never empty, and those two inserts are the only ones in the kernel that
run inside the service that turns tracing on. The buffer pointer and the event
enable bits are both set a few lines above, so neither can be found in any other
state on the way in, and both inserts sat at 4 of 12.

A new test enables with a buffer sized from the kernel's own structures to hold
exactly one event, which puts both inserts on the wrap boundary, and with three
notifications: one that counts, one that filters the running event's own class,
and one that turns tracing off. The last two are what reach the second insert's
filtered and no-buffer arms, and both are ordinary application behaviour rather
than a contrivance - a notification that stops tracing is what an application
capturing a single bufferful of history does. The forced-state passes hold one
SMP protection across the write, the enable and the restore.

tx_trace_enable.c:392 goes to 12 of 12 and :391 to 10 of 12 on the union of the
eight configurations, from 4 each. The two arms left are the first insert's own
copies of the filtered and no-buffer tests, which nothing can reach between the
assignments above it and the insert. 133/133 in each of the eight, and 50
standalone repeats of the new test green in every one of them.

Assisted-by: Claude Code (Opus 5) &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Covered the four trace services that carry an insert of their own</title>
<updated>2026-09-20T21:55:38Z</updated>
<author>
<name>Frédéric Desbiens</name>
<email>frederic.desbiens@eclipse-foundation.org</email>
</author>
<published>2026-09-20T21:55:38Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/threadx.git/commit/?id=3f56bfe4826367ba5f5fad802130ce2af4650f9f'/>
<id>urn:sha1:3f56bfe4826367ba5f5fad802130ce2af4650f9f</id>
<content type='text'>
The interrupt control, the two ISR inserts and the user event insert are part of
the tracing machinery rather than users of it, and nothing drove their inserts
beyond the conditions testcontrol.c and threadx_trace_basic_test.c happen to
present. The two ISR inserts were the whole of this suite's unstable set: their
buffer-wrap arms were reached when the buffer happened to wrap under an insert,
which is why they moved between runs.

A new test walks the services once per condition the insert distinguishes, and
positions the buffer one entry short of its end rather than waiting for it to
wrap, under one SMP protection and asserting the wrap per service. The interrupt
control is driven at the outermost level only, and is left out of the pass that
runs from interrupt context: _tx_thread_interrupt_control takes the Linux
critical section on every call and hands it back in full only on an enable, so a
pair completed where the section is already held leaves it two levels deeper and
locks the process. Its disable half runs inside the protection, where the insert
is, and its enable half once the protection is released. Its own forced-state
passes reach the two arms the interrupt pass would have covered.

All four sites go to 12 of 12 on the union of the eight configurations, from
7, 5, 5 and 6. 133/133 in each of the eight, and 50 standalone repeats of the
new test green in every one of them.

Assisted-by: Claude Code (Opus 5) &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Covered the MISRA shim's stack check and its two conversions</title>
<updated>2026-09-20T21:55:38Z</updated>
<author>
<name>Frédéric Desbiens</name>
<email>frederic.desbiens@eclipse-foundation.org</email>
</author>
<published>2026-09-20T21:55:38Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/threadx.git/commit/?id=32def98fc0e277f1fa782646f15112938d74f15b'/>
<id>urn:sha1:32def98fc0e277f1fa782646f15112938d74f15b</id>
<content type='text'>
Three regions of tx_misra.c had no caller in any of the eight build
configurations. The thread stack check is reached through TX_THREAD_STACK_CHECK,
whose call sites sit inside TX_ENABLE_STACK_CHECKING and which is redirected to
the shim only under TX_MISRA_ENABLE, and no configuration defines both. The user
timer derivation's six call sites are behind TX_TIMER_ENABLE_PERFORMANCE_INFO,
three of them behind TX_TIMER_PROCESS_IN_ISR as well. The trace entry conversion
has no caller in common_smp/src at all.

A new test drives all three through the macro the kernel itself uses, so the
shim and the in-line form the other builds compile are asserted to agree. The
stack check is the one with logic in it, and is given a scratch thread one fault
at a time: a cleared identifier, either stack fence overwritten, the recorded
high-water mark moved above the stack pointer and below the stack. That thread
is created with TX_DONT_START on a fenced buffer of the test's own and never
runs, so no faulted state is ever visible to the scheduler.

tx_misra.c goes from 138/163 lines and 16/30 branch outcomes to 163/163 and
30/30 on the union of the eight configurations. 133/133 in each of the eight,
and 50 standalone repeats of the new test green in every one of them.

Assisted-by: Claude Code (Opus 5) &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Reduced the byte pool owner change test to a single claim thread</title>
<updated>2026-09-20T17:30:13Z</updated>
<author>
<name>Frédéric Desbiens</name>
<email>frederic.desbiens@eclipse-foundation.org</email>
</author>
<published>2026-09-20T17:30:13Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/threadx.git/commit/?id=d2ef8a80940090452f6e826dd1fd6903decc1595'/>
<id>urn:sha1:d2ef8a80940090452f6e826dd1fd6903decc1595</id>
<content type='text'>
The test put one claim thread on every core the test thread was not using, and
waited for all of them to be claiming before it started searching. On a machine
with fewer processors than the port simulates cores that is not a safe wait: the
claim threads walk the pool holding the protection, so two of them can keep the
third from making any progress, and the test reports the arrangement as never
having arrived. One CI run in seven failed that way.

One claim thread is all the construct needs. It asks whether the pool can change
hands under a walk, and a single other core answers it; further claim threads
spend most of their time contending with each other rather than with the thread
under test. The walk count goes up from five to twenty to keep the margin the
extra threads were providing.

Between 360 and 1,320 changes of pool ownership per run over six runs in the two
configurations that schedule it slowest, against the one the coverage needs, in
2.5 seconds. 129/129 in each of eight configurations with retries disabled.

Assisted-by: Claude Code (Opus 5) &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Covered the byte pool search retry when the pool changes owner</title>
<updated>2026-09-20T17:10:47Z</updated>
<author>
<name>Frédéric Desbiens</name>
<email>frederic.desbiens@eclipse-foundation.org</email>
</author>
<published>2026-09-20T17:10:47Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/threadx.git/commit/?id=7e6960210fec350a3c5f0857e88665a9ac6ec69b'/>
<id>urn:sha1:7e6960210fec350a3c5f0857e88665a9ac6ec69b</id>
<content type='text'>
Where the SMP byte pool search gives the protection up, it checks on taking it
back whether the pool is still its own, and if not it delays, resets the walk and
claims the pool again. Three branch outcomes and eight lines of that were never
executed. The pool owner is written in six places, all of them kernel services,
and none can run on the searching thread's own core while that thread is inside
the walk, so the construct needs a second core in use. The existing contention
test does not reach it because its pool is too small to open the window at all:
the protection is only given up once per multiple block search limit.

A new test keeps the test thread on its own core and puts one claim thread on
each of the others, each making the same unsatisfiable request and so walking the
same pool. A claim thread is then usually already holding the protection when the
test thread reaches a window, which is the state the construct is written
against. The test waits for every claim thread to be mapped and claiming before
it starts searching, rather than sleeping a fixed number of ticks, because how
long the rebalance takes varies by configuration. It asserts the arrangement
rather than the retry, which restores the owner the walk had already set and
leaves nothing a test can read.

Three outcomes and eight lines, measured at 48,971 changes of owner in a run of
2.6 seconds. This is the second test in the suite that needs more than one core.
129/129 in each of eight configurations with retries disabled, and sixty
standalone repeats clean in the three configurations that schedule it slowest.

Assisted-by: Claude Code (Opus 5) &lt;noreply@anthropic.com&gt;
</content>
</entry>
</feed>
