Skip to content

fix(libc): skip guest exit handlers on host window close - #5843

Merged
adriadam10 merged 1 commit into
boykopovar:mainfrom
Ondra97:codex/fix-window-close-exit
Oct 15, 2026
Merged

adriadam10 merged 1 commit into
boykopovar:mainfrom
Ondra97:codex/fix-window-close-exit

Conversation

@Ondra97

@Ondra97 Ondra97 commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

What

Closing the native VLC v0.4 (PPSA85300) window aborts the process, as reported in the #5791 validation. SDL_QUIT calls LibcRequestExit_nid_postfix, whose detached thread currently runs the guest finalizers. VLC still has a joinable C++ thread object; its destructor calls terminate() and then abort().

The asynchronous host exit request now uses LibcExitWithoutHandlers_nid_no_patch from #5236. It runs the registered runtime shutdown callbacks, flushes the host streams and terminates without guest or host exit handlers. The new guest_requested_exit mode reuses the existing exit fixture: shutdown must complete, another guest thread must stay parked during shutdown, both kinds of exit handler must remain uncalled, and a second request with status 7 must leave the first request's status 0 intact. Its parent checks the child's actual exit code.

#5236 is merged into main. This PR now contains only the host-window-close change and its regression (three files). #5978 remains a separate dependent follow-up for explicit guest exit() and return from main.

Tested

Rebase validation on Windows 11 Pro build 26300, WinLibs GCC 15.2.0, Ninja Release: head eb8146b73, based on main 0ae1deb85. #5236 is merged into this base.

  • Full default build, including the patched runtime libraries, passed.
  • All 20 focused tests passed, with no failures or skips: eight exit modes, eleven related shutdown/lifecycle cases and patched_libraries.
  • python tools/check_conventions.py --base origin/main, git diff --check and python tools/check_main_sync.py --base origin/main passed; clean merge, 0 behind at publication.
  • git range-diff confirms that the host-window-close patch is unchanged. Production Process.cpp is byte-identical to the original title-tested PR head. The PR now has one commit and three changed files; the merged prerequisite is no longer carried as a separate commit.

No new title run or Linux run was performed for this rebase. The original title validation below was performed before the rebase:

Windows 11 Pro build 26300, WinLibs GCC 15.2.0, Ninja Release. Original head e0748f372, based on main 5a6ad0ed3 plus #5236:

  • Full default build and patched runtime libraries passed. All 19 relevant tests passed in 2.37 s: asynchronous requested exit, SystemService exit/parameters, quick/immediate exit, return from main, relaunch/nested exit, KillApp/status/parameters, application heap ordering, thread atexit, user context/exit and four AGC shutdown tests.
  • Negative control: the new child mode on fix(libSceSystemService): end LoadExec exit without running guest exit handlers #5236 alone still prints Guest shutdown completed followed by Guest exit handler ran; CTest fails in 0.17 s. That PR alone does not fix host window closure.
  • Original official VLC v0.4, converted with --windows --registry --windows-diagnostics --windows-fixed-base 0x400000, including its own libc module. Executable ELF SHA-256: eec51934aa2debed99152c3996f39a41be25e17d9ca14de01cee2d17b62d8e3f. All 132 installed runtime files were checked against the build by SHA-256.
  • On main 550764236, a visible 20 s run ends with 0xc0000409 after CloseMainWindow() returns true. GDB reaches LibcExit -> CxaFinalize; the guest destructor at 0x2261f30 calls termination when its first word is nonzero, and abort_nid_postfix is reached from 0x22c49af. The adjacent functions carry thread::join failed and thread::detach failed, and the destructor matches libc++'s thread destructor. Process.cpp is byte-identical on that baseline and final base 5a6ad0ed3.
  • With this change, a visible 20 s run with the normal draw cache and a separate 60 s run with APS5_NO_DRAW_SRT_ENTRIES=1 both close normally with exit code 0, without a timeout or forced kill. The latter displays the complete welcome screen and 16 language buttons. Disabling that cache isolates shutdown from the rendering bug fixed by fix(agc): validate mesh index descriptors on cached draws #5791; this PR changes no rendering code. Media playback and a local Linux run were not tested.
  • python tools/check_conventions.py --base origin/main, git diff --check and python tools/check_main_sync.py --base origin/main passed; clean merge, 0 behind.

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt
  • No notes, investigation .md files or images added to the repository (evidence recorded in this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Unblocks: PPSA85300 VLC (PPSA85300) #5732 (abort on host window closure)
  • GPUs tested: NVIDIA GeForce RTX 4070 Ti SUPER, driver 617.14 / 32.0.16.1714, Windows 11 Pro build 26300
  • AI-assisted: yes — Codex

@MarcZX10

Copy link
Copy Markdown
Contributor

I have a separate follow-up for #5931 covering explicit guest exit() and return-from-main: run guest finalizers while VideoOut/AGC are still available, then run the registered shutdown callbacks. It leaves your host-window-close path on LibcExitWithoutHandlers unchanged and declares Depends on: #5843. The regression checks the shutdown token is still live during a guest finalizer, including the normal nested-exit path. Please let me know if that stacking order conflicts with your intended change; I will keep the scope separate.

@Ondra97

Ondra97 commented Oct 14, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @MarcZX100, that ordering fits the intended scope of #5843. The dependency order would be #5236 → #5843 → your follow-up.

Please keep guest_requested_exit and guest_system_exit passing: both must still skip guest and host exit handlers. For explicit guest exit() and return-from-main, keeping VideoOut/AGC available through the remaining finalizers, including nested exit(), makes sense. The shutdown callbacks should then run once.

AI-assisted: yes. — Codex

@ahmad3a4

Copy link
Copy Markdown
Contributor

Windows check with the title from #5931. With this PR (e0748f3) on main ed835aa, closing Syobon Action (PPSA47402) with WM_CLOSE ends with exit code 0 in 3 of 3 runs. On main e34c479 it aborted 4 of 4 times with libc: exit thread cannot wait for itself. guest_requested_exit and the other exit tests pass here too.

The run was stacked with #5978, so the merge resolution is in #5978 (comment). Keep LibcRunShutdown_nid_postfix() in LibcExitWithoutHandlers_nid_no_patch once StartExit no longer runs it.

AI-assisted.

@Ondra97

Ondra97 commented Oct 14, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @ahmad3a4 for validating the combined tree. The merge resolution is correct: once StartExit() no longer runs shutdown, LibcExitWithoutHandlers_nid_no_patch() must call LibcRunShutdown_nid_postfix() before flushing and terminating.

@MarcZX100, one remaining coverage gap in #5978: guest_nested_exit currently checks the remaining handler and exit code, but does not register a shutdown callback or check the token. Please extend it to verify that the remaining finalizer sees a live token and that shutdown runs exactly once afterward.

AI-assisted: yes. — Codex

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 14, 2026
@Ondra97
Ondra97 force-pushed the codex/fix-window-close-exit branch from e0748f3 to beaf86d Compare October 14, 2026 20:19
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 14, 2026
@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 14, 2026
@Ondra97
Ondra97 force-pushed the codex/fix-window-close-exit branch from beaf86d to eb8146b Compare October 14, 2026 21:17
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 14, 2026
@Ondra97
Ondra97 marked this pull request as ready for review October 14, 2026 21:25
@screamm

screamm commented Oct 15, 2026

Copy link
Copy Markdown
Contributor

Windows/NVIDIA check with VLC (PPSA85300 v0.4, catalog release).

  • Head eb8146b73 merged onto main 2559e9623: clean, no conflicts (merge 87c4dc4a6). Windows 11 Pro 26220, WinLibs MinGW-w64 GCC 15.2.0 r7, Ninja, Release, NVIDIA GeForce RTX 4070 (driver 596.21).
  • Build: full default build and libs pass, no new warnings.
  • --repeat until-fail:3: guest_requested_exit, guest_system_exit, guest_system_exit_parameters, guest_quick_exit, guest_immediate_exit, guest_return_from_main, guest_system_relaunch, guest_nested_exit: 8/8, 3 of 3.
  • Negative control: the same guest_system_exit_tests.exe --requested-exit-driver with main's libc.prx first on PATH prints Guest shutdown completed, Guest exit handler ran, FATAL: abort() (SIGABRT) (3 of 3).
  • ctest -j8 --timeout 120 -E '^agc_driver_|^video_out_flip': 813/813 passed (2 skipped, the same as on main: agc_host_import_sparse, guest_video_out_wqhd_detection_no_vulkan).
  • VLC relinked with relinker --windows --registry unused-filter=0 --windows-fixed-base 0x400000, identical procedure for both builds, visible window, WM_CLOSE posted to it at 45 s:
Build Runs After WM_CLOSE Window title at close
main 2559e96 3 exit 0xC0000409 after 0.8 / 3.2 / 1.4 s VLC | FPS: 46.23 (2458), 48.98 (2263), 41.19 (1647)
main + #5843 2 exit 0 after 0.8 / 1.4 s VLC | FPS: 57.05 (3020), 75.20 (2692)

Neither build prints a stop line. Every log ends at [src/Thread.cpp:527 RunThread] RunThread entry=0x22d3f60 arg=00000020000228c0 self=…, and on main the abort leaves only the exit code. Both builds show the same screen (gradient and page dots; the text needs #5791).

Verdict: on NVIDIA, closing the VLC window now exits 0 instead of aborting, with no test regressions.

AI-assisted: yes (Claude Code)

@milescoviello

Copy link
Copy Markdown
Contributor

A Linux run with the title from #5931: Syobon Action (PPSA47402, catalog 01.001.000), Ubuntu 24.04, GCC 13.3, Release, main ab9a476. The window was closed with wmctrl -c 20 s in, while the title was presenting:

AI-assisted: yes

@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.

Pull request Shared files not compared
PR 6044 core/libs/prx/libSceSystemService/CMakeLists.txt
core/libs/tests/GuestSystemExit.cpp
PR 6447 core/libs/prx/libc/src/Process.cpp

@adriadam10 adriadam10 self-assigned this Oct 15, 2026
@adriadam10

Copy link
Copy Markdown
Collaborator

Checked on the PR merged onto current main: build and scoped ctest green (119/119, no skips). guest_requested_exit fails when the Process.cpp change is reverted and passes with it; LibcExitWithoutHandlers_nid_no_patch still runs the shutdown callbacks through StartExit. Windows and Linux title runs by @ahmad3a4, @screamm and @milescoviello cover what we can't run here; merging once the full Build is green.

@adriadam10
adriadam10 merged commit b8aca1e into boykopovar:main Oct 15, 2026
15 checks passed
@MarcZX10

Copy link
Copy Markdown
Contributor

I added the missing coverage to #5978 and rebased that PR onto current main (de974eb83). The nested-exit child now registers a shutdown callback and a remaining finalizer that asserts the shutdown token is still live; the exact marker sequence also verifies the finalizer runs before shutdown and the callback runs once. The existing exit-code and remaining-handler checks stay in place.

The test source syntax check and conventions check pass. I have not rerun the runtime CTest on this host; the earlier attempt stopped at the host CPU-feature guard before entering the test body. Hosted checks are starting on the rebased head.

@Ondra97
Ondra97 deleted the codex/fix-window-close-exit branch October 17, 2026 14:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants