Repository navigation
Fix intermittent exit AV: RenderThread::Terminate kicked over a busy frame - #32
Merged
Merged
Conversation
…minate Terminate() kicked while the render thread could still be Busy with the previous frame. Set(Kick) overwrote Busy, the render thread set Idle when done and exited, so the last submitted frame never ran on it and Renderer::Shutdown replayed the whole frame on the main thread after the renderer was torn down. Wait for Idle first, pump the last frame on the render thread, then kick once more so it observes IsRunning() == false and returns. m_IsRunning is atomic.
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.
What
RenderThread::Terminate()now waits for the in-flight frame before its final pump. The last submitted frame then runs on the render thread, and a final kick lets the thread exit. Applied to both the Windows and Linux render threads.m_IsRunningis nowstd::atomic<bool>.Why
This fixes the intermittent
0xC0000005in ReleaseEditor.exeat exit. It hit 1–5 of every 16 golden-harness launches, and also some manual closes during a run.Terminate()used to dom_IsRunning = false; Pump();with no wait first. If the render thread was stillBusywith frame N-1,Pump()'sSet(Kick)overwroteBusy. The render thread then setIdle, saw!IsRunning()and returned, so frame N never ran on it.Renderer::Shutdownthen replays the leftover command queue on the main thread. By thenStorageImageClear::Shutdownhas nulleds_Layoutands_RendererDatahas been deleted.CmdSetPipelineLayout(*s_Layout)readsnull+0x148, and the process faults. The fault RVA (0x605D21) disassembles to exactly that read inside the inlinedCommandBufferVK::SetPipelineLayout.Whether it fires depends on whether the render thread has finished frame N-1 by the time
~ApplicationreachesTerminate. That is why it never reproduced under a debugger.Neither interleaving can deadlock after the final kick. If the render thread is waiting, it runs the already-executed (empty) queue and exits. If it has already seen
!IsRunning(), it has exited and the kick is a no-op. Nothing waits forIdleafter that kick.Verification
golden_run.py --scenes Benchmark --features --config release: 16/16 OK on the fixed build. No Editor.exe AV in the Application event log, and no CoreCLR dumps (DOTNET_DbgEnableMiniDump=1). Baseline builds the same day crashed 5/16 (p1B), 1/16 (p1A), plus one exit-time AV (p1B2). The p1B "mid-run" deaths were manual window closes, which take the sameTerminatepath.LinuxRenderThread.cpp, but not compiled on Linux.Regeneration
Not needed (no files added or removed).
Docs
.claude/docs/Threading.md: added the "neverKick()while the render thread isBusy" rule and theTerminatesequence.