1
0
mirror of https://github.com/dockur/windows.git synced 2026-07-27 21:42:36 +07:00

fix: Prevent races during interactive shutdown (#1907)

This commit is contained in:
Kroese
2026-07-20 16:18:19 +02:00
committed by GitHub
parent 520be36ed5
commit 7996bacb39
+92 -22
View File
@@ -13,6 +13,7 @@ QEMU_PTY="$QEMU_DIR/qemu.pty"
QEMU_END="$QEMU_DIR/qemu.end"
CONSOLE_PID="$QEMU_DIR/console.pid"
CONSOLE_SOCKET="$QEMU_DIR/console.sock"
QEMU_START_PID="$QEMU_DIR/qemu.start.pid"
_trap() {
@@ -65,11 +66,58 @@ displayReason() {
readQemuPid() {
local -n _pid="$1"
local file
if [ ! -s "$QEMU_PID" ] || ! read -r _pid <"$QEMU_PID"; then
return 1
fi
for file in "$QEMU_START_PID" "$QEMU_PID"; do
if [ -s "$file" ] && read -r _pid < "$file"; then
return 0
fi
done
return 1
}
qemuPidFile() {
local -n _file="$1"
_file="$QEMU_PID"
[ -s "$QEMU_START_PID" ] && _file="$QEMU_START_PID"
return 0
}
terminateQemu() {
local file=""
qemuPidFile file
sKill "$file"
return 0
}
waitQemuExit() {
local timeout="${1:-10}"
local file=""
qemuPidFile file
waitPidFile "$file" "$timeout"
}
waitQemuPid() {
local -n _pid="$1"
local cnt=0 value=""
while ! readQemuPid value; do
sleep 0.02
cnt=$((cnt + 1))
(( cnt >= 50 )) && return 1
done
_pid="$value"
return 0
}
@@ -99,7 +147,7 @@ boot() {
fi
error "Timeout while waiting for QEMU to boot the machine, aborting..."
sKill "$QEMU_PID"
terminateQemu
return 0
}
@@ -136,8 +184,7 @@ ready() {
forceKillQemu() {
local reason="$1"
local pid=""
local display
local pid="" display
! readQemuPid pid && return 0
! isAlive "$pid" && return 0
@@ -193,9 +240,8 @@ cleanupHelpers() {
startConsole() {
local cnt=0
local pid=""
local output="${1:-/dev/tty}"
local cnt=0 pid=""
rm -f -- "$CONSOLE_SOCKET" "$CONSOLE_PID"
@@ -240,10 +286,34 @@ stopConsole() {
return 0
}
startQemu() {
rm -f -- "$QEMU_START_PID"
(
trap '' INT QUIT
# shellcheck disable=SC2016
exec setsid -f -w sh -c '
file=$1
shift
"$@" &
pid=$!
printf "%s\n" "$pid" > "$file" || exit 1
rc=0
wait "$pid" 2>/dev/null || rc=$?
exit "$rc"
' sh "$QEMU_START_PID" "$@"
) </dev/null &
return 0
}
finish() {
local reason=$1
local failed=0
local reason=$1 failed=0
if [ ! -f "$QEMU_END" ] && (( reason != 0 )); then
failed=1
@@ -259,7 +329,7 @@ finish() {
cleanupHelpers
if ! waitPidFile "$QEMU_PID" 10; then
if ! waitQemuExit 10; then
warn "Timed out while waiting for $(app) to exit!"
fi
@@ -278,7 +348,6 @@ normalizeTimeout() {
local term_grace=3 # seconds before loop ends to send SIGTERM
local cleanup_grace=3 # seconds reserved after the loop for cleanup
local min
TIMEOUT=$(strip "$TIMEOUT")
if [[ ! "$TIMEOUT" =~ ^[0-9]+$ ]]; then
@@ -293,7 +362,7 @@ normalizeTimeout() {
cleanup_grace=4
fi
min=$((term_grace + cleanup_grace + 1))
local min=$((term_grace + cleanup_grace + 1))
(( TIMEOUT < min )) && (( TIMEOUT = min ))
wait_until=$((TIMEOUT - cleanup_grace))
@@ -315,11 +384,12 @@ sendAcpiShutdown() {
abortDuringSetup() {
local code="$1"
info "Cannot send ACPI signal during $(app) setup, aborting..."
sKill "$QEMU_PID"
terminateQemu
if ! waitPidFile "$QEMU_PID" 5; then
if ! waitQemuExit 5; then
warn "Timed out while waiting for $(app) to exit!"
fi
@@ -328,10 +398,9 @@ abortDuringSetup() {
waitForShutdown() {
local cnt=0
local pid="$1"
local name="$APP"
local slp
local slp cnt=0
while (( cnt <= wait_until && SHUTDOWN_SKIP == 0 )); do
@@ -342,7 +411,7 @@ waitForShutdown() {
! isAlive "$pid" && break
# Workaround for stale/zombie QEMU pid file
[ ! -s "$QEMU_PID" ] && break
[ ! -s "$QEMU_START_PID" ] && [ ! -s "$QEMU_PID" ] && break
if (( cnt == sigterm_at )); then
info "${name^} is still running, sending SIGTERM... ($cnt/$wait_until)"
@@ -364,8 +433,7 @@ waitForShutdown() {
graceful_shutdown() {
local sig="$1"
local pid=""
local code=0
local pid="" code=0
[[ $BASHPID != "$TRAP_PID" ]] && return
@@ -390,8 +458,10 @@ graceful_shutdown() {
echo && info "Received $sig signal, sending ACPI shutdown signal..."
if ! readQemuPid pid; then
warn "QEMU PID file ($QEMU_PID) does not exist?"
finish "$code"
if ! interactive || ! waitQemuPid pid; then
warn "QEMU PID file does not exist?"
finish "$code"
fi
fi
if [ -z "$pid" ] || ! isAlive "$pid"; then