Skip to content

The isolated step runs for every plugin of a pass, and again after it could not run - #271

Merged
linuxnow merged 4 commits into
mainfrom
fix/isolated-step-private-server
Oct 31, 2026
Merged

linuxnow merged 4 commits into
mainfrom
fix/isolated-step-private-server

Conversation

@linuxnow

@linuxnow linuxnow commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

On a Raspberry Pi 5, plugin-qualify-sync --system --isolated-only measured one plugin and read isolated.no-private-server for the next 151, exit 0.

Cause. Each step starts a private jackd with the same name. A pass is synchronous, so the process never reaped the jackd it had stopped. A jackd that had a client leaves its entry in the server table, and a zombie counts as alive, so the next start exited with server already active. Starting jackd under a shell that stays as its parent made the second start work on the Pi. The existing live test ran the step only once.

Fix.

  • jackd runs under a shell that waits for it, so it is reaped when it ends. The adapter pass uses the same starter.
  • completeIsolated runs a not-run step again and replaces it. Before this, the record kept not-run and no pass tried again, although isolatedPass says one does.

Tests. In the first commit, the new tests are red on CI with isolated.no-private-server and expected undefined to be isolated.

  • Live: the step three times in a row on the fixture.
  • Unit: a not-run step is retried and replaced, and a refused one is not.
  • the pass moves each pin asserted that a second pass does nothing, which was the bug. It now expects the not-run step to run again.
  • cpuPercent > 0 failed on CI once at 0, so that assertion is now >= 0.

Not proven yet: a whole pass on the Pi with this build. The device is measuring. It runs once this is released.

…nning

On a Pi 5 a pass ran the step for one plugin; the next 151 read
isolated.no-private-server, because jackd refused the name it had used for the
first one. A step that did not run was then never tried again.
… could not run

jackd now runs under a shell that waits for it. A pass is synchronous, so the sync
could not reap jackd, and an unreaped jackd that had a client stayed in JACK's
server table as alive: the next start under that name read 'server already
active', and the step read isolated.no-private-server for every plugin after
the first.

A step that could not run decided nothing, so completeIsolated runs it again and
puts the new step in its place, as the pass's own comment says.

The fixture's worker can use no measurable CPU in the window, so the live test
asks only for a figure.
@linuxnow
linuxnow marked this pull request as ready for review October 31, 2026 07:02
@linuxnow

Copy link
Copy Markdown
Contributor Author

What I measured on the Pi 5 (jackd 1.9.22~dfsg-4, plugin-qualify 0.18.2, plugin-hostd 0.15.4), with spawnedIsolatedRunner() called in a loop from a small script. No sync and no records involved.

run jackd started by first step second step
no client, four start/stop rounds of startPrivateJack node, directly up up every time
SAFEDistortion, then ZamDelay node, directly isolated not-run after 58 ms
same, SERVER_STOP_MS raised to 30000 node, directly isolated not-run after 57 ms
same, jackd on PATH is a script that does exec /usr/bin/jackd "$@" >> log 2>&1 same pid as node's child isolated not-run; log says 'omx-qualify-<pid>-128' server already active, Failed to open server
same, jackd on PATH is a script that runs it in the background and waits (below) a bash child of node isolated isolated

The script that worked:

#!/bin/bash
/usr/bin/jackd "$@" >> log 2>&1 &
p=$!
trap "kill -TERM $p" TERM
wait $p; rc=$?; wait $p 2>/dev/null; exit $rc

What this shows:

  • It takes a client on the first server to trigger it. With no client, restarts under the same name work.
  • It is not the stop timeout: the wait was never used up, and 30 s changes nothing.
  • /dev/shm holds none of the server's files after the stop, so removing them does not help. What is left is outside them, in JACK's server table.

I ran this working script only once, with two plugins, under bash. It differs from the wrapper in this PR in three ways: it runs under bash rather than sh (dash on Debian, whichever CI uses), it has no wait inside the trap, and its stdio goes to a file rather than being ignored. I have not tried the PR's wrapper on the Pi, because the device is measuring. So I can't say which difference matters on CI, or whether the Pi and CI differ at all.

A server name unique to each start would avoid the name clash, but as far as I remember JACK's server table has few slots, and an entry that looks alive holds one. I have not checked that. If a run needs it on the Pi, tell me: it can go in between two batches.

The shell's trap sent a second TERM, and a jackd that did not end was then killed with its group, the shell included, so
nothing reaped it and the next start read 'server already active'. Reproduced on Debian's jackd2 with a killed client. A
TERM now reaches jackd once and giving up kills jackd alone: 8 restarts of 8 came up. Such a stop takes about 2 s.
@linuxnow
linuxnow merged commit 9b35e15 into main Oct 31, 2026
23 checks passed
@linuxnow
linuxnow deleted the fix/isolated-step-private-server branch October 31, 2026 07:26
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