demo: two guests of 384 MiB, and a busy message for the rest (#116)
Captain Bob, 2026-11-07: 'Limit guests and have a Busy, try back in a few minutes.' start-session.sh takes one of DEMO_MAX_GUESTS slots (default 2), a lock it holds for the session's life (flock -n: two visitors cannot both take the last one; QEMU and the bridge are started without its descriptor); with every slot taken, the visitor's terminal says every machine is busy and to try back in a few minutes, and the session ends without a machine. The service: DEMO_MAX_GUESTS=2, RuntimeDirectory for the locks, ttyd's --max-clients 6 so a visitor over the limit reaches the message. The guest: 384 MiB (v4 boots from 256 MiB, refuses at 128; measured, #116). Tested here: every slot held -> the busy message; slot 1 held -> slot 2 taken. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
This commit is contained in:
+5
-3
@@ -3,8 +3,10 @@
|
||||
# A session resumes a machine saved by make-snapshot.sh, and QEMU can resume a saved machine only
|
||||
# into the same machine: the same board, CPU, memory, firmware and devices. Both scripts build the
|
||||
# command line here, so they cannot drift apart. It is the machine `make -f kernel/Makefile
|
||||
# ARCH=amd64 qemu` boots (q35, TCG, 1 GiB, OVMF, the ISO as a CD), less what a visitor must not
|
||||
# have: no network device, no Artemis disk, no display, and QEMU's seccomp sandbox on.
|
||||
# ARCH=amd64 qemu` boots (q35, TCG, OVMF, the ISO as a CD) -- in 384 MiB, not its 1 GiB: v4 boots
|
||||
# to Zuse's prompt from 256 MiB, refuses at 128 ("no memory for the block chain"), measured
|
||||
# 2026-11-07 (#116) -- less what a visitor must not have: no network device, no Artemis disk, no
|
||||
# display, and QEMU's seccomp sandbox on.
|
||||
#
|
||||
# demo_qemu_args <state-dir> <vars.fd> -> fills the array QEMU_ARGS
|
||||
#
|
||||
@@ -18,7 +20,7 @@ demo_qemu_args() {
|
||||
QEMU_ARGS=(
|
||||
-machine q35,accel=tcg
|
||||
-cpu qemu64,+rdrand
|
||||
-m 1024
|
||||
-m 384 # v4 boots from 256 MiB; 384 leaves room (#116)
|
||||
-smp 1
|
||||
-drive "if=pflash,format=raw,readonly=on,file=$OVMF_CODE"
|
||||
-drive "if=pflash,format=raw,file=$vars"
|
||||
|
||||
@@ -13,8 +13,13 @@ User=starshipos-demo
|
||||
Group=starshipos-demo
|
||||
Environment=DEMO_STATE=/var/lib/starshipos-demo
|
||||
Environment=DEMO_SESSION_LIMIT=1800
|
||||
# -m: sessions at once -- each a QEMU of about 1 GiB and most of a core (issue #116 measures it)
|
||||
ExecStart=/usr/bin/ttyd --port 7681 --interface lo --writable --max-clients 3 \
|
||||
Environment=DEMO_MAX_GUESTS=2
|
||||
# the guests' slot locks (start-session.sh): /run/starshipos-demo, made for this user, gone at stop
|
||||
RuntimeDirectory=starshipos-demo
|
||||
# --max-clients: the guests and a few more, so a visitor over the limit reaches the busy message
|
||||
# instead of a refused connection; still a cap on open connections
|
||||
# each guest a QEMU of 384 MiB and most of a core (demo/qemu-args.sh; #116)
|
||||
ExecStart=/usr/bin/ttyd --port 7681 --interface lo --writable --max-clients 6 \
|
||||
--client-option titleFixed=StarshipOS --client-option disableLeaveAlert=true \
|
||||
/opt/starshipos-demo/demo/start-session.sh
|
||||
Restart=on-failure
|
||||
|
||||
+24
-3
@@ -12,8 +12,29 @@ here=$(cd "$(dirname "$0")" && pwd)
|
||||
. "$here/qemu-args.sh"
|
||||
dir=${1:-${DEMO_STATE:-/var/lib/starshipos-demo}}
|
||||
limit=${DEMO_SESSION_LIMIT:-1800} # seconds a session may last
|
||||
guests=${DEMO_MAX_GUESTS:-2} # machines at once: 384 MiB each (qemu-args.sh, #116)
|
||||
slots=${DEMO_SLOTS:-/run/starshipos-demo} # a lock file per machine
|
||||
|
||||
[ -f "$dir/state" ] || { echo "The demo is not set up yet: no saved machine in $dir." >&2; exit 1; }
|
||||
|
||||
# One of $guests slots, or a busy message (Captain Bob, 2026-11-07: "Limit guests and have a Busy,
|
||||
# try back in a few minutes"). A slot is a lock this script holds for the session's life (flock -n:
|
||||
# two visitors cannot both take the last one); it goes when the script does, however it ends. The
|
||||
# machine's processes are started without the lock's descriptor ({slot}>&-), so it is this
|
||||
# script's alone.
|
||||
mkdir -p "$slots"
|
||||
slot=
|
||||
for i in $(seq 1 "$guests"); do
|
||||
exec {fd}>"$slots/slot-$i.lock"
|
||||
if flock -n "$fd"; then slot=$fd; break; fi
|
||||
exec {fd}>&-
|
||||
done
|
||||
if [ -z "$slot" ]; then
|
||||
printf '\r\nEvery StarshipOS machine is busy right now (%d at once on this small server).\r\n' "$guests"
|
||||
printf 'Try back in a few minutes.\r\n'
|
||||
sleep 20
|
||||
exit 0
|
||||
fi
|
||||
tmp=$(mktemp -d "${TMPDIR:-/tmp}/starshipos-session.XXXXXX")
|
||||
trap 'rm -rf "$tmp"' EXIT
|
||||
cp "$dir/vars.fd" "$tmp/vars.fd"
|
||||
@@ -28,13 +49,13 @@ printf 'Try: 3 4 + . : SQUARE DUP * ; 7 SQUARE .\r\n\r\n'
|
||||
qemu-system-x86_64 "${QEMU_ARGS[@]}" \
|
||||
-chardev "socket,id=con,path=$tmp/con.sock,server=on,wait=off" -serial chardev:con \
|
||||
-qmp "unix:$tmp/qmp.sock,server=on,wait=off" -monitor none \
|
||||
-incoming "file:$dir/state" </dev/null &
|
||||
-incoming "file:$dir/state" </dev/null {slot}>&- &
|
||||
qemu=$!
|
||||
( sleep "$limit"; kill "$qemu" 2>/dev/null ) &
|
||||
( sleep "$limit"; kill "$qemu" 2>/dev/null ) {slot}>&- &
|
||||
timer=$!
|
||||
# The bridge is a tracked child too: bash runs a trap only once its foreground command returns,
|
||||
# so a hang-up would otherwise wait on the bridge. `wait` returns to the trap at once.
|
||||
python3 -I "$here/console.py" "$tmp/qmp.sock" "$tmp/con.sock" 0<&0 &
|
||||
python3 -I "$here/console.py" "$tmp/qmp.sock" "$tmp/con.sock" 0<&0 {slot}>&- &
|
||||
bridge=$!
|
||||
trap 'kill "$bridge" "$qemu" "$timer" 2>/dev/null; rm -rf "$tmp"' EXIT
|
||||
trap 'exit 0' HUP TERM INT
|
||||
|
||||
Reference in New Issue
Block a user