fix: wait for the chvt that switches back

rb_chvt returned as soon as the console asked for was in front. The
console to go back to usually is already, so the launcher could end
before a chvt started late had run: under load the log missed the
switch back. The switch now also waits for chvt to end. A fake chvt
that starts 1.2 s late made the old code fail every time.
This commit is contained in:
Abdessamad Derraz committed 2026-10-28 11:35:47 +01:00
1 parent 8247fd2a96
commit 23c1f3121f
2 files changed
+34 -4

No files matched your search

+13 -2
View File
@@ -542,6 +542,15 @@ rb_font_restore() {
RB_FONT_BACK=""
}
# Whether a job this shell started is still running.
rb_job_running() {
local job
for job in $(jobs -rp); do
[ "$job" = "$1" ] && return 0
done
return 1
}
# The number of the console in front, which a switch has to come back to.
rb_active_vt() {
local active
@@ -558,13 +567,15 @@ rb_active_vt() {
# chvt, and whether the console really came to the front. chvt waits for the
# switch (VT_WAITACTIVE): a compositor that keeps the display would hold it
# forever, so it gets 3 s.
# forever, so it gets 3 s. The switch is done once chvt has ended too: the
# console to go back to is often in front already, and returning on that
# alone left the launcher ending before a chvt started late had run.
rb_chvt() {
local pid waited=0
$ESUDO chvt "$1" >> "$RB_LOG" 2>&1 &
pid=$!
while [ "$waited" -lt 12 ]; do
[ "$(rb_active_vt)" = "$1" ] && return 0
[ "$(rb_active_vt)" = "$1" ] && ! rb_job_running "$pid" && return 0
rb_nap 0.25
waited=$((waited + 1))
done
+21 -2
View File
@@ -625,6 +625,8 @@ printf '%s\\n' "$(basename "$0") $*" >> "$FAKE_STATE/tools.log"
# compositor that keeps the display (FAKE_CHVT_REFUSED) leaves chvt waiting
# in VT_WAITACTIVE and the console in front unchanged.
FAKE_CHVT = """#!/bin/sh
# A loaded machine starts the process late (FAKE_CHVT_DELAY seconds).
[ -n "$FAKE_CHVT_DELAY" ] && sleep "$FAKE_CHVT_DELAY"
printf '%s\\n' "chvt $*" >> "$FAKE_STATE/tools.log"
[ -n "$FAKE_CHVT_REFUSED" ] && exec sleep 30
[ -n "$RB_VT_ACTIVE" ] && printf 'tty%s\\n' "$1" > "$RB_VT_ACTIVE"
@@ -1509,13 +1511,13 @@ class TheBatoceraPort(unittest.TestCase):
self.assertEqual(chvt, [f"chvt {self.number}", f"chvt {self.home}"])
device.assert_console_restored()
def test_a_refused_console_switch_shows_nothing_on_an_unseen_console(self):
def test_a_refused_console_switch_shows_nothing_on_an_unseen_console(self, **slow):
"""The compositor keeps the display: chvt waits and the console in
front stays the same. The launcher switches back and stops, instead
of an interface no key reaches."""
device, ports = self.device(FAKE_PGREP="0")
proc = device.run(["/bin/bash", str(ports / "RetroBIOS.sh")], FAKE_CHVT_REFUSED="1",
**self.console_switch(device))
**self.console_switch(device), **slow)
self.assertEqual(proc.returncode, 125)
self.assertLess(device.elapsed, 20)
self.assertEqual(device.tui_calls(), [])
@@ -1526,6 +1528,23 @@ class TheBatoceraPort(unittest.TestCase):
self.assertIn(f"console {self.number} did not come to the front", log)
self.assertNotIn("\x1bc", device.screen)
def test_the_switch_back_is_waited_for_on_a_slow_machine(self):
"""The console to go back to was already in front, so rb_chvt
returned before its chvt had even started, and the launcher ended
with the switch back still pending: under load the log missed
"chvt 2". A chvt that starts 1.2 s late made it fail every time."""
self.test_a_refused_console_switch_shows_nothing_on_an_unseen_console(
FAKE_CHVT_DELAY="1.2")
def test_a_slow_console_switch_still_comes_back(self):
device, ports = self.device(FAKE_PGREP="0")
proc = device.run(["/bin/bash", str(ports / "RetroBIOS.sh")], FAKE_CHVT_DELAY="1.2",
**self.console_switch(device))
self.assertEqual(proc.returncode, 0, proc.stderr.decode())
chvt = [line for line in device.tools() if line.startswith("chvt")]
self.assertEqual(chvt, [f"chvt {self.number}", f"chvt {self.home}"])
self.assertEqual((device.root / "active").read_text(), f"tty{self.home}\n")
def test_xterm_that_cannot_open_hands_over_to_the_console(self):
device, ports = self.device(DISPLAY=":0", FAKE_PGREP="0")
device.tool("xterm", FAKE_TERMAPP)