RISC-V LR/SC Loops: Preserve the Conditions Required for Eventual Success
A short RISC-V compare-and-update loop works in one build but repeatedly fails after instrumentation is added. The stored value is aligned and no obvious competitor is visible. Before blaming the reservation hardware, check whether the emitted loop still qualifies for the architecture's constrained LR/SC progress guarantee.
The guarantee concerns a precisely restricted instruction sequence and memory environment. It does not apply to every loop that happens to contain load-reserved and store-conditional instructions.
Inspect the whole constrained loop
The pinned Zalrsc specification limits a constrained loop to at most 16 instructions placed sequentially in memory, comprising the LR/SC sequence and its failure-retry code.
Between LR and SC, only the permitted base-integer instructions and their specified compressed forms may execute. Loads, stores, backward jumps, taken backward branches, JALR, FENCE and SYSTEM instructions are excluded. Retry code may branch backward to repeat the sequence, but otherwise has the same restrictions.
A logging store, counter CSR read or helper call can therefore invalidate the conditions even if it does not modify the word being updated. Inspect final disassembly, including instrumentation and retry paths, rather than counting statements in a C macro.
The successful SC must also use the same effective address and data size as the latest LR. The memory region must have the LR/SC eventuality property, communicated by the execution environment. Naturally aligned ordinary RAM is not, by itself, a complete statement of that platform contract.

Unconstrained does not mean almost guaranteed
The specification permits unconstrained sequences to succeed on some implementations and fail indefinitely on others. Portable code using them must detect repeated failure and fall back to an alternative that does not depend on the unconstrained sequence.
Do not repair a diagnostic build by assuming that a larger arbitrary retry limit restores the architectural guarantee. It may bound the application's own waiting, but it does not make the emitted sequence constrained. Prefer moving observation outside the sensitive loop or using an established platform primitive whose implementation contract is maintained.
The SC result is zero on success and nonzero on failure. Portable failure handling should not depend on a particular nonzero value being a detailed explanation of why the reservation was lost.
Interpret progress without promising per-hart success
For a constrained loop in an appropriate region, the specified eventual outcome includes more than the current hart completing a successful SC. Another hart's successful SC or an interfering write can satisfy the stated condition; the current hart can also exit or trap.
This is not a finite retry bound or a guarantee that every contending hart avoids starvation. Continuous writes to the reservation set by other harts or devices can prevent the desired completion. A timing-critical caller needs a separately justified bounded policy rather than treating architectural eventuality as a deadline.
The cache-block operation specification adds another relevant event: another hart performing a cache-block management or zero operation on the reservation set can satisfy the eventuality condition. Thus a background maintenance path can matter even when it is not an ordinary competing scalar store.
Diagnose reservation interference at the right granularity
The reservation set may be larger than the word loaded. Another hart's store anywhere in that set can invalidate the reservation. Device writes have a narrower mandatory rule: writes overlapping the bytes loaded by LR must cause failure, while writes elsewhere in the reservation set need not do so.
A proposed investigation therefore records the final loop, region guarantee and possible writers or maintenance operations. It should avoid inserting diagnostic memory accesses into the loop it is trying to qualify. No LR/SC test was executed here; the deliverable is a source-grounded check of when progress reasoning is valid.