Skip to content

Fix the race when reading the emulator's process group - #23

Merged
jpcottin merged 1 commit into
mainfrom
ci/fix-setsid-pgid-race
Jul 26, 2026
Merged

Fix the race when reading the emulator's process group#23
jpcottin merged 1 commit into
mainfrom
ci/fix-setsid-pgid-race

Conversation

@jpcottin

Copy link
Copy Markdown
Owner

The bug

setsid(2) runs asynchronously in the child, so for a brief window after backgrounding the launcher its pid still reports the shell's process group. #21 read the pgid exactly once:

EMU_PID=$!
EMU_PGID="$(ps -o pgid= -p "$EMU_PID" 2>/dev/null | tr -d ' ')"

When that read lands too early, the guard sees EMU_PGID == SELF_PGID, correctly refuses to group-kill our own step, and silently falls back to a single-pid kill. So the process-group scoping that #21 was meant to introduce was not reliably active.

Observed on the runner in 1 of 4 boot cycles during #22's run, and 0 of 4 during #21's — which is why it slipped through. The consequence was mild (adb emu kill is the primary shutdown path, and the fallback still terminates the launcher), but the scoping is the entire point of that change.

The fix

Poll until the pgid settles, giving up only if the emulator dies or after 10s. The first iteration is byte-for-byte what the old code did, so this can only ever do better — it just retries instead of surrendering.

Also logs the resolved pgid on success. Previously a successful isolation printed nothing, so the logs couldn't distinguish "worked" from "never checked" — only the failure was visible.

Verification

The race does not reproduce on an unloaded dev machine: 0 losses in 40 trials. Forcing the timing the runner exhibits — a child that lingers in the parent's process group for 300ms before setsid — separates the two clearly:

trials=10   OLD single-read lost: 10/10   NEW polling lost: 0/10

Only emulator-preview-multirun changes; the other five jobs parse byte-identical to main.

setsid(2) runs asynchronously in the child, so for a brief window after
backgrounding the launcher its pid still reports the *shell's* process
group. Reading the pgid exactly once loses that race intermittently: the
guard then sees EMU_PGID == SELF_PGID, correctly refuses to group-kill our
own step, and silently drops to the single-pid fallback -- so the process
group scoping added in #21 was not reliably active.

Observed on the runner in 1 of 4 boot cycles (#22's run); 0 of 4 in #21's,
which is why it was missed. Consequence was mild -- 'adb emu kill' is the
primary shutdown path and the fallback still terminates the launcher -- but
the scoping is the whole point of that change.

Poll until the pgid settles instead, giving up only if the emulator dies or
after 10s. The first iteration is identical to the previous single read, so
this can only ever do better. Also log the resolved pgid, so a future run
shows whether isolation actually happened rather than staying silent.

The failure cannot be reproduced on an unloaded dev machine (0 losses in 40
trials); forcing the timing -- a child that lingers in our process group for
300ms before setsid -- the old single read loses 10/10 and the polling
version loses 0/10.
@jpcottin
jpcottin merged commit d0762d9 into main Jul 26, 2026
13 checks passed
@jpcottin
jpcottin deleted the ci/fix-setsid-pgid-race branch July 26, 2026 05:17
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.

1 participant