Skip to content

gamescopereaper, steamcompmgr: propagate the primary child's exit status - #2541

Open
BiNeurale wants to merge 2 commits into
ValveSoftware:masterfrom
BiNeurale:propagate-exit-status
Open

BiNeurale wants to merge 2 commits into
ValveSoftware:masterfrom
BiNeurale:propagate-exit-status

Conversation

@BiNeurale

Copy link
Copy Markdown

gamescope exits with status 0 whatever the command after -- returns (#2540). This makes gamescopereaper return the primary child's exit status (128 + N for signal N), and gamescope return it in turn, except when gamescope itself is being shut down, which still exits 0. A command that cannot be started exits 127, like a shell.

Tested with --backend headless on CachyOS (RADV RENOIR):

command before after
true 0 0
sh -c 'exit 7' 0 7
false 0 1
sh -c 'kill -SEGV $$' 0 139
sh -c 'kill -KILL $$' 0 137
/nonexistent/cmd 0 127
SIGTERM to gamescope while the child runs 0 0

New tests in tests/test_process.cpp run the built gamescopereaper; meson test passes (75/75).

Closes #2540

gamescope exits with status 0 whatever the command after `--` returns,
so a failing command looks like a success to the calling script.
gamescopereaper waited for its child and then returned 0, and the
gamescope-wait thread dropped the reaper's status.

The reaper now returns the primary child's exit status, or 128 + N if it
was killed by signal N, like a shell. gamescope returns that status,
unless it was shutting down already: when gamescope itself is closed it
still exits 0. A command that cannot be started now exits 127 instead
of 0.

Closes: ValveSoftware#2540
@JROtto5

JROtto5 commented Nov 6, 2026

Copy link
Copy Markdown

Thanks, I'll leave mine and go with this one. I tested d1a0134 nested (--backend wayland) on KDE Wayland with an RTX 5070 Ti, to cover NVIDIA alongside your RADV headless runs:

command exit
true 0
sh -c 'exit 7' 7
false 1
sh -c 'kill -SEGV $$' 139
sh -c 'kill -KILL $$' 137
sh -c 'kill -TERM $$' 143
/nonexistent/cmd 127
SIGTERM to gamescope while the child runs 0 (3/3)
gamescopereaper alone, sent SIGTERM 143

meson test passes here too (76/76).

One small thing from reading it, which I couldn't trigger: if the reaper gets SIGTERM after spawning but before its first WaitForAllChildren, s_bRun is already false, the wait is skipped and the child is reaped by the final argument-less wait, so the reaper returns 0. Waiting on nPrimaryChild after KillAllChildren when it hasn't been reaped yet would close that. It's minor either way.

…e wait

If SIGTERM (or SIGHUP, SIGINT, SIGQUIT) reaches the reaper after the
primary child is spawned but before the reaper starts waiting for it,
s_bRun is already false and the wait is skipped. The child is then
reaped by the final argument-less WaitForAllChildren(), its status is
lost and the reaper returns 0 instead of 143. With --respawn the same
window returned the status of the previous instance.

Wait for the primary child explicitly when it has not been reaped yet.

Reported-by: JROtto5 <222316562+JROtto5@users.noreply.github.com>
@BiNeurale

Copy link
Copy Markdown
Author

Thanks a lot @JROtto5, both for testing on NVIDIA nested and for reading the code closely: you're right about that window.

I could reproduce it under gdb by stopping the reaper right after SpawnProcess and delivering SIGTERM there: the reaper exited 0 instead of 143. With --respawn the same window returned the status of the previous instance instead.

Fixed in 62deb3e, with you credited as Reported-by: if the primary child hasn't been reaped yet, the reaper now waits for it explicitly after KillAllChildren, before the final wait. The same gdb run now exits 143 with and without --respawn, meson test passes, and the headless end-to-end checks are unchanged (0, 7, 1, 139, 137, 127, and 0 when gamescope itself is closed).

@JROtto5

JROtto5 commented Nov 6, 2026

Copy link
Copy Markdown

Thanks for the credit, and for chasing it down under gdb. I re-ran the same NVIDIA nested set on 62deb3e: exits are unchanged (0, 7, 1, 139, 137, 127; 0 when gamescope itself gets SIGTERM, 2/2), gamescopereaper alone exits 143 on SIGTERM, and meson test passes (76/76). Looks good to me.

@BiNeurale

Copy link
Copy Markdown
Author

Thanks @JROtto5 for re-running the whole NVIDIA set on 62deb3e and for the review, much appreciated. From my side the PR is ready whenever a maintainer has time to look at it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Exit status of the launched command is not propagated: gamescope always exits 0

2 participants