#!/usr/bin/bash
#
# Internal helper for btest-bg-run.

is_windows=0
case "$(uname -s)" in
    MINGW* | MSYS* | CYGWIN*) is_windows=1 ;;
esac

# On Windows, kill the child's process tree using its Windows PID.
# taskkill /T terminates the process and all its descendants.
# MSYS_NO_PATHCONV prevents MSYS from interpreting /F, /T, /PID as paths.
win_kill_tree() {
    if [ $is_windows -eq 1 ]; then
        local wpid=""
        # Prefer the live /proc lookup: after exec the Windows PID may
        # differ from the value captured at startup in .winpid.
        if [ -n "$pid" ] && [ -f /proc/"$pid"/winpid ]; then
            wpid=$(cat /proc/"$pid"/winpid)
        elif [ -f .winpid ]; then
            wpid=$(cat .winpid)
        fi
        if [ -n "$wpid" ]; then
            MSYS_NO_PATHCONV=1 taskkill /F /T /PID "$wpid" &>/dev/null
        fi
    fi
}

cleanup() {
    # Ignore SIGTERM during cleanup to prevent terminating
    # this process when sending signals to the process group.
    trap true SIGTERM

    if [ ! -e .exitcode ]; then
        echo 15 >.exitcode

        # Send SIGTERM to all processes in the process group
        # of the calling process.
        #
        # This should terminate any well-behaved background
        # commands that were spawned by the program under test
        # unless they started their own process group.
        #
        # On Windows (without setsid) the helper shares a process
        # group with the parent, so kill 0 would take out the
        # entire test harness.  Only kill the child directly.
        if [ $is_windows -eq 0 ]; then
            kill 0 &>/dev/null
        fi

        if [ -n "$pid" ]; then
            kill -0 "$pid" &>/dev/null && kill "$pid"
            sleep 1
            kill -0 "$pid" &>/dev/null && kill -9 "$pid" && echo 9 >.exitcode
        fi

        # Fallback: on Windows, use taskkill to ensure the entire
        # process tree is terminated even if kill missed descendants.
        win_kill_tree
    fi
}

trap "cleanup" EXIT

eval "$* &"

pid=$!
echo $$ >.pid

# Record the child's Windows PID so that btest-bg-wait can
# reliably terminate it even if MSYS PIDs become stale.
# Also record the child's MSYS PID (.winchildpid): btest-bg-wait
# can use it to look up the *current* Windows PID via /proc at kill
# time, which is more reliable than .winpid because exec may change
# the Windows PID.
# Guard: /proc entry disappears if the child exits before we get here.
if [ $is_windows -eq 1 ] && [ -f /proc/$pid/winpid ]; then
    cat /proc/$pid/winpid >.winpid
    echo $pid >.winchildpid
fi

wait $pid
rc=$?

# On Windows, TerminateProcess cannot invoke clean signal handlers the
# way Unix signals do.  A process killed by SIGTERM exits with code 15,
# which bash maps to 128+15=143.  When a test intentionally kills a
# process (e.g., supervisor shutdown), this is the expected outcome, so
# treat it as success.
if [ $is_windows -eq 1 ] && [ $rc -eq 143 ]; then
    rc=0
fi

echo $rc >.exitcode
pid=""
