Ask the engine to stop when the session ends - #141
Merged
Conversation
Nothing in the tree handled WM_QUERYENDSESSION or WM_ENDSESSION, so a session end killed the engine thread inside hts_main2 mid-request, with no clean stop and no chance to mark the mirror interrupted. CMainFrame now reuses the Cancel button's stop path, factored out of Cinprogress::OnStopall as RequestMirrorStop(), registers a shutdown block reason so Windows can name us on the screen that waits, and gives the engine a bounded fifteen seconds to unwind. The wait pumps sent messages, or the engine thread's own SendMessage into the UI thread would deadlock against it. Signed-off-by: Xavier Roche <xroche@gmail.com> Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Xavier Roche <roche@httrack.com>
The wait added by the first cut pumped messages so the engine's end-of-mirror SendMessage could land, but that handler opens an unconditional AfxMessageBox when hts_is_exiting() is 2 -- the value htscore.c sets on exactly the early stop this path produces (stat_files <= 0 and under 32 KB received). PeekMessage does not return until the box is dismissed, the box paints behind the shutdown screen, and Windows force-kills the process on HungAppTimeout mid-unwind. Drop the wait, the pump and the shutdown block reason. WM_QUERYENDSESSION now requests the same stop the Cancel button requests and returns at once; the engine unwinds on whatever time the rest of the shutdown leaves it, which is strictly more than master gives it. A static guard keeps the request to one per process, since a second one sets termine_requested and turns the clean stop into an abrupt abort. Signed-off-by: Xavier Roche <xroche@gmail.com> Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Xavier Roche <roche@httrack.com>
A static "already asked" flag lasted the life of the process, so a shutdown the user cancelled consumed the one ask: the next mirror then logged off with no stop request at all, straight back to master's behaviour. The engine's own soft_term_requested is the right guard. RequestMirrorStop() escalates on it, CShellApp::init_lance() clears it before every mirror, and nothing else writes it, so it is already scoped to exactly one mirror. Both handlers together still ask once, and a cancelled shutdown leaves the next mirror its own ask without depending on WM_ENDSESSION(FALSE) being delivered. Selftest gains that sequence as a fifth row, which the per-process flag fails. Signed-off-by: Xavier Roche <xroche@gmail.com> Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Xavier Roche <roche@httrack.com>
Both frame handlers now call SessionEndStop(bEnding), so the selftest can reach a shutdown the user cancels and assert the mirror keeps running. The two stop helpers return an enum naming what they found rather than a BOOL only the test read. The smoke test pins the new count; it has no catch-all. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Xavier Roche <roche@httrack.com>
Both sides added a selftest block and its pin at the same place; keep both, and keep master's CrashReportHeader() startup line. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Xavier Roche <roche@httrack.com>
xroche
marked this pull request as ready for review
August 23, 2026 09:23
xroche
enabled auto-merge (squash)
August 23, 2026 09:23
#140 added its pin at the same anchor; keep both. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Xavier Roche <roche@httrack.com>
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.
WinHTTrack ignores
WM_QUERYENDSESSION, so logging off kills the engine thread mid-write. The frame now asks the engine to stop, the same request the Cancel button makes once confirmed, and returns TRUE straight away. It cannot wait for the stop: waiting means pumping messages, and the engine's end-of-mirrorSendMessagethen opens a modal box on top of the handler, which is the hang Windows force-kills. The engine unwinds on whatever time the rest of the shutdown leaves it, andsoft_term_requestedmakeslance()writeinterrupted.lock, so the project reopens on "continue interrupted download".Both handlers route through
SessionEndStop(bEnding). The ask is guarded onsoft_term_requestedrather than on a flag of our own, becauseinit_lance()clears it before every mirror:OnQueryEndSessionandOnEndSessionfiring together cannot escalate totermine_requestedand abort abruptly, and a shutdown the user cancels still leaves the next mirror its own ask. The selftest covers six cases, the cancelled shutdown among them, where the mirror has to be left running.CI cannot log off, so the unwind needs a VM: start a mirror on a large site, log off within five seconds, log back in, and check that no crash dialog appeared, that
hts-cache/interrupted.lockexists, and that reopening the project preselects "continue interrupted download". Repeat after a minute of mirroring, so more than 32 KB is cached, and once more cancelling the shutdown at the confirmation prompt.