Skip to content

Make the driver's atomic flag helpers actually atomic - #25

Merged
terjeio merged 1 commit into
grblHAL:masterfrom
DavidLDawes:fix-atomic-flag-ops
Sep 25, 2026
Merged

terjeio merged 1 commit into
grblHAL:masterfrom
DavidLDawes:fix-atomic-flag-ops

Conversation

@DavidLDawes

Copy link
Copy Markdown

Problem

bitsSetAtomic, bitsClearAtomic and valueSetAtomic in src/driver.c are plain read-modify-writes; the interrupt masking a real MCU relies on is commented out. In the simulator, the "ISRs" run on the hardware thread while grblHAL's main loop runs on the grbl thread. One example is the serial RX handler that sets EXEC_STATUS_REPORT when a ? arrives. Both threads update the same flags word, so their updates can interleave and one gets lost.

The visible symptom is that some ? status requests never get a reply, most noticeably during motion.

Fix

Use real atomic read-modify-writes: __atomic_fetch_or, __atomic_fetch_and and __atomic_exchange_n (__ATOMIC_SEQ_CST). This is a single-file change to src/driver.c.

Evidence

Probe: 400 ? requests per trial, about 50 ms apart, during a long G91 G1 X1000 F200 move at -t 1, over the -p telnet connection. A request counts as lost if no status report arrives within 2 s.

Build Lost Slowest answered
master (91eda77), two runs of 4 trials 50 / 3200 (~1.6%) 34 ms
This branch, 4 trials 0 / 1600 30 ms

So it's loss, not latency: every answered request is fast, and the rest never get a reply. I found this downstream, in an MCP server that drives grblHAL and runs its hardware test scripts against the simulator in CI. A status-polling test there failed 4 of 14 runs on master and passed 14 of 14 with this change.

Caveat

The __atomic_* builtins are GCC/Clang-specific. That covers this repo's CI matrix (gcc, clang, MinGW gcc on Windows), but an MSVC build would need _Interlocked* equivalents. I've only built and tested with gcc 14 on Linux. Happy to adjust if you'd prefer a different primitive, for example C11 <stdatomic.h> (already included in driver.c) with the pointed-to fields declared _Atomic.

🤖 Generated with Claude Code

bitsSetAtomic/bitsClearAtomic/valueSetAtomic were plain read-modify-writes
(the interrupt masking a real MCU would use is commented out). In the
simulator the "ISRs" - e.g. the serial RX handler that sets
EXEC_STATUS_REPORT for a '?' - run on the hardware thread while grblHAL's
main loop runs on the grbl thread, so the two threads' updates to the same
flags word could interleave and one would be lost.

Visible as '?' status requests that never get a reply: 50 of 3200 probes
during motion at -t 1 (about 1.6%), with every answered one back in 30 ms or
less - loss, not latency. With __atomic_fetch_or / __atomic_fetch_and /
__atomic_exchange_n: 0 of 1600. Builds with gcc and clang (the compilers
this repo's CI matrix uses); MinGW gcc on Windows supports the same builtins.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment thread src/driver.c
}

// Helper functions for setting/clearing/inverting individual bits atomically (uninterruptable)
//

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please tell the Claude thing that I do not want (parts of) the PR summary in the code, IMO it is not needed.

@terjeio
terjeio merged commit 742bd18 into grblHAL:master Sep 25, 2026
@terjeio

terjeio commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

Thanks.

Re: Caveat
I'll leave this as-is until it becomes an issue.

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.

3 participants