From b92ef011bf12cc9d4f4e2025604d105278bc2c9e Mon Sep 17 00:00:00 2001 From: Nicholas Dudfield Date: Fri, 25 Sep 2026 10:37:49 +0700 Subject: [PATCH] refactor(consensus): compute and store the busy flag through one private template publishBusy() delegates to publishBusyAfter(), which keeps the same busyMu_ critical section, predicate and relaxed store, and runs a caller-supplied step between compute and store. Production passes an empty step; tests use it to hold a computed value before its store. --- src/xrpld/app/consensus/ConsensusExtensions.h | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/xrpld/app/consensus/ConsensusExtensions.h b/src/xrpld/app/consensus/ConsensusExtensions.h index 7af8577d5d..7d8b5aa3a8 100644 --- a/src/xrpld/app/consensus/ConsensusExtensions.h +++ b/src/xrpld/app/consensus/ConsensusExtensions.h @@ -654,8 +654,7 @@ public: void publishBusy() { - std::lock_guard lock(busyMu_); - busyPublished_.store(computeBusyUnlocked(), std::memory_order_relaxed); + publishBusyAfter([] {}); } // Phase changes happen in the tick, which is not a member. The store and @@ -692,6 +691,19 @@ public: } private: + // Compute and store the busy flag under one busyMu_ critical section. + // afterCompute runs between the two, on the publishing thread, with + // busyMu_ held; tests use it to hold a computed value before its store. + template + void + publishBusyAfter(AfterCompute&& afterCompute) + { + std::lock_guard lock(busyMu_); + auto const busy = computeBusyUnlocked(); + afterCompute(); + busyPublished_.store(busy, std::memory_order_relaxed); + } + bool computeBusyUnlocked() const {