Skip to content

fix(test): bound race-round barrier spin so a missing release flag fails instead of hanging - #39

Open
danikdanik wants to merge 1 commit into
alexgreensh:mainfrom
danikdanik:fix/race-round-unbounded-spin
Open

danikdanik wants to merge 1 commit into
alexgreensh:mainfrom
danikdanik:fix/race-round-unbounded-spin

Conversation

@danikdanik

Copy link
Copy Markdown
Contributor

What

_race_round() in test_windows_portability.sh held 10 forked racers on an unbounded busy-spin (while [ ! -f "$flag" ]; do :; done). If the release flag can never appear — the mktemp workdir was swept mid-round, : > "$flag" failed, or TMP was empty — every racer burns ~65% CPU forever while wait parks the suite.

Why it matters

Observed on macOS (bash 3.2.57): a single conformance run parked for 16+ hours with ~7 cores of pure busy-loop, because conformance.sh invokes suites with no timeout and the test has no bound of its own. The failure is silent — nothing in the output says the suite wedged.

How

  • Racers now concede when the workdir is gone or a 15s SECONDS deadline hits — a broken barrier reports FAIL instead of hanging.
  • _race_round returns a distinct ERR on barrier failure (flag create fails, or won/flag vanish mid-round), and both callers stop on the first broken round — no more 40×15s slow-burn on a persistent failure, and 0 winners can no longer masquerade as a "control caught non-atomic claim" pass.
  • wait $pids instead of bare wait; true > instead of : > so a redirect failure can't exit POSIX shells before || runs; entry guard for empty/missing TMP.

Repro / verification

  • Healthy run (unchanged): passed=20 failed=0 in ~15s, control still catches 20/20.
  • Fault injection (the incident): delete the mktemp workdir while racers spin.
    • Before: parent parked at wait in S, 10 children at ~65% CPU in R, indefinitely.
    • After: FAIL: race barrier broken — release flag never appeared (round N), suite exits rc=1 in ~2s.
# minimal reproducer of the mechanism (pre-fix)
TMP="$(mktemp -d)"; flag="$TMP/go.$$"
for i in $(seq 10); do ( while [ ! -f "$flag" ]; do :; done ) & done
sleep 0.3; rm -rf "$TMP"; : > "$flag" 2>/dev/null   # create fails silently
wait   # parks forever; racers spin forever

Residual (out of scope): conformance.sh still has no per-suite timeout, so a suite that wedges outside a bounded spin can still park the gate — worth a follow-up.

…ils instead of hanging

_race_round held 10 forked racers on `while [ ! -f "$flag" ]; do :; done`
with no bound. If the release flag can never appear — the mktemp workdir
was swept mid-round, the flag create failed, or TMP was empty — each
racer burns ~65% CPU forever while `wait` parks the suite. Observed:
~7 cores of busy-loop holding a conformance run for 16+ hours.

Each racer now concedes when the workdir is gone or a 15s deadline hits,
and a broken barrier returns a distinct ERR result so callers stop on the
first broken round — 0 winners can no longer masquerade as a control
catch, and a failed flag create kills the round's racers immediately
instead of burning 40 rounds of deadline.

Verified on bash 3.2.57/macOS: healthy run still 20/20 (~15s); deleting
the workdir mid-race exits rc=1 in ~2s with 'release flag never
appeared' instead of hanging.
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