Fix connection data race probably causing flaky tests#392
Closed
KonradBreitsprecherBkd wants to merge 1 commit into
Closed
Fix connection data race probably causing flaky tests#392KonradBreitsprecherBkd wants to merge 1 commit into
KonradBreitsprecherBkd wants to merge 1 commit into
Conversation
Signed-off-by: Konrad Breitsprecher <Konrad.Breitsprecher@vector.com>
Contributor
Author
|
Spun again on Debug and Release for 10k Times each with stress, could no longer reproduce the initial hang. |
Contributor
Author
|
Took the wrong route here, this was NOT the cause of the hanging test. Although promise_already_satisfied is thrown in rare cases, this is catched and does not cause a deadlock or any hanging test. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fix data race in ConnectKnownParticipants::UpdateStage
Problem
ITest_Internals_ParticipantModes.test_SyncAutonomousReqwas intermittently failing with astd::future_error(promise_already_satisfied) thrown fromVAsioConnection::OnConnectKnownParticipantsWaitingForAllRepliesat_startWaitingForParticipantHandshakes.set_value().Root cause
ConnectKnownParticipants::UpdateStage()performs a non-atomic check-then-set on_connectStage. Although_connectStageisstd::atomic, the existing_mutexonly guards the_peersiteration inside the lambdas — it never covers the stage transition itself.UpdateStage()can run concurrently on two threads:JoinSimulation→ConnectToKnownParticipants→StartConnecting(which callsUpdateStage()after issuing the async connects); andOnConnectPeerSuccess→UpdateStage()).Because the IO worker is already running the shared
_asioIoContextwhenStartConnectingissues the connects, a fast (local domain-socket) connect can complete and drive the IO-threadUpdateStage()while the caller-threadUpdateStage()is still mid-transition. Both threads read_connectStage == CONNECTING, both observeallWaitingForReplies == true, and both fireOnConnectKnownParticipantsWaitingForAllReplies()→set_value()twice. The second call throws.The
try/catch(...)aroundset_value()swallows the exception, so it does not crash the process, but the underlying data race on_connectStageis undefined behavior and the real source of the flakiness. TheWAITING_FOR_ALL_REPLIES → ALL_REPLIES_RECEIVEDtransition has the same exposure.Fix
Serialize the entire
UpdateStage()transition body with a dedicated_stageMutex, so the check-then-set runs atomically. Once one thread completes a transition, the next re-reads the already-advanced_connectStageand skips the block, so each stage callback fires exactly once.Lock ordering is consistent (
_stageMutex → _mutex); no listener callback invoked withinUpdateStage()re-entersConnectKnownParticipants, so there is no deadlock or recursion risk.Changes
ConnectKnownParticipants.hpp: addstd::mutex _stageMutex.ConnectKnownParticipants.cpp: acquire_stageMutexat the top ofUpdateStage().Testing
ITest_Internals_ParticipantModes.test_SyncAutonomousReqin a loop to confirm the flake no longer reproduces.