#!/bin/bash
# vm_slot.sh (runs ON THE VM, installed at /root/qa58/vm_slot.sh by _tools/vm_motionqa.sh): hold one of the page-render Chrome slots
# while <command> runs. A, 29 Oct. Max 2 page Chromes, and fewer while the VM's own players run: slots = 2 - (held player locks,
# /tmp/stickbrawl-lock-player.N with a live pid). Parks while the 1-min load is over 16 (4 vCPU; PORT-T9 4 Nov) or MemAvailable is under 2.5 GB.
# A slot whose holder pid is gone is reclaimed. The command tree runs at nice 15 (re-niced every 3 s).
BASE=/tmp/k58qa-slot; slot=""
alive() { [ -n "$1" ] && kill -0 "$1" 2>/dev/null; }
cap() {
  local held=0 d p
  for d in /tmp/stickbrawl-lock-player.[0-9]*; do [ -d "$d" ] || continue; p=$(cat "$d/pid" 2>/dev/null); alive "$p" && held=$((held+1)); done
  local n=$((2 - held)); [ $n -lt 1 ] && n=1   # (29 Oct, coordinator: a floor of 1 page Chrome even while both players run)
  # (PORT-T9 4 Nov, the VM LOAD RULE: KS VM steps wait while the 1-min load is > 16; the old 5-min > 10 park never cleared at the VM's normal ~20)
  local l1; l1=$(awk '{print int($1)}' /proc/loadavg); [ "$l1" -gt "${VM_SLOT_LOADMAX:-24}" ] && n=0
  local ma; ma=$(awk '/MemAvailable/ {print int($2/1024)}' /proc/meminfo); [ "$ma" -lt 2560 ] && n=0
  echo $n
}
waited=0
while [ -z "$slot" ]; do
  N=$(cap)
  for i in 1 2; do
    d="$BASE.$i"; p=$(cat "$d/pid" 2>/dev/null)
    if [ -d "$d" ] && [ -n "$p" ] && ! alive "$p"; then rm -f "$d/pid"; rmdir "$d" 2>/dev/null; fi
    [ "$i" -gt "$N" ] && continue
    if mkdir "$d" 2>/dev/null; then echo $$ > "$d/pid"; slot="$d"; break; fi
  done
  if [ -z "$slot" ]; then [ $((waited % 60)) -eq 0 ] && echo "[vm_slot] waiting (slots now $N, load5 $(awk '{print $2}' /proc/loadavg))" >&2; sleep 5; waited=$((waited+5)); fi
done
trap 'rm -f "$slot/pid"; rmdir "$slot" 2>/dev/null' EXIT
# (PORT-T9 4 Nov, the coordinator: a bake's Chrome renderer ran at nice 0 at VM load 64 - Chrome, as root, resets its renderers' priority)
# the whole tree runs at nice >= VM_SLOT_NICE (15): the command starts at it and a watcher re-nices every descendant every 3 s
NI=${VM_SLOT_NICE:-15}
nice -n "$NI" "$@" &
cp=$!
desc() { local c; for c in $(pgrep -P "$1" 2>/dev/null); do echo "$c"; desc "$c"; done; }
while kill -0 "$cp" 2>/dev/null; do
  for q in $(desc "$cp"); do [ "$(ps -o ni= -p "$q" 2>/dev/null | tr -d ' ')" -lt "$NI" ] 2>/dev/null && renice -n "$NI" -p "$q" >/dev/null 2>&1; done
  sleep 3
done
wait "$cp"
