153 lines
3.0 KiB
Bash
Executable File
153 lines
3.0 KiB
Bash
Executable File
#! /usr/bin/env bash
|
|
#
|
|
# Usage: btest-bg-wait [-k] <timeout>
|
|
#
|
|
# Waits until all of the background process spawned by btest-bg-run
|
|
# have finished, or the given timeout (in seconds) has been exceeded.
|
|
#
|
|
# If the timeout triggers, all remaining processed are killed. If -k
|
|
# is not given, this is considered an error and the script abort with
|
|
# error code 1. If -k is given, a timeout is not considered an error.
|
|
#
|
|
# Once all processes have finished (or were killed), the scripts
|
|
# merges their stdout and stderr. If one of them returned an error,
|
|
# this script does so as well
|
|
|
|
if [ "$1" == "-k" ]; then
|
|
timeout_ok=1
|
|
shift
|
|
else
|
|
timeout_ok=0
|
|
fi
|
|
|
|
if [ $# != 1 ]; then
|
|
echo "usage: $(basename "$0") [-k] <timeout>"
|
|
exit 1
|
|
fi
|
|
|
|
timeout=$(($1 * 100))
|
|
|
|
procs=$(cat .bgprocs)
|
|
|
|
rm -f .timeout
|
|
touch .timeout
|
|
|
|
function check_procs {
|
|
for p in $procs; do
|
|
if [ ! -e "$p/.exitcode" ]; then
|
|
return 1
|
|
fi
|
|
done
|
|
|
|
# All done.
|
|
return 0
|
|
}
|
|
|
|
function kill_procs {
|
|
for p in $procs; do
|
|
if [ ! -e "$p/.exitcode" ]; then
|
|
kill -1 "$(cat "$p/.pid")" 2>/dev/null
|
|
cat "$p"/.cmdline >>.timeout
|
|
if [ "$1" == "timeout" ]; then
|
|
touch "$p/.timeout"
|
|
fi
|
|
fi
|
|
done
|
|
|
|
sleep 1
|
|
|
|
for p in $procs; do
|
|
if [ ! -e "$p/.exitcode" ]; then
|
|
kill -9 "$(cat "$p/.pid")" 2>/dev/null
|
|
sleep 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
function collect_output {
|
|
rm -f .stdout .stderr
|
|
|
|
if [ $timeout_ok != 1 ] && [ -s .timeout ]; then
|
|
{
|
|
echo "The following processes did not terminate:"
|
|
echo
|
|
|
|
cat .timeout
|
|
|
|
echo
|
|
echo "-----------"
|
|
} >>.stderr
|
|
fi
|
|
|
|
for p in $procs; do
|
|
pid=$(cat "$p/.pid")
|
|
cmdline=$(cat "$p/.cmdline")
|
|
|
|
{
|
|
printf "<<< [%s] %s\\n" "$pid" "$cmdline"
|
|
cat "$p"/.stdout
|
|
echo ">>>"
|
|
} >>.stdout
|
|
|
|
{
|
|
printf "<<< [%s] %s\\n" "$pid" "$cmdline"
|
|
cat "$p"/.stderr
|
|
echo ">>>"
|
|
} >>.stderr
|
|
done
|
|
}
|
|
|
|
trap kill_procs EXIT
|
|
|
|
while true; do
|
|
|
|
if check_procs; then
|
|
# All done.
|
|
break
|
|
fi
|
|
|
|
timeout=$((timeout - 1))
|
|
|
|
if [ $timeout -le 0 ]; then
|
|
# Timeout exceeded.
|
|
kill_procs timeout
|
|
|
|
if [ $timeout_ok == 1 ]; then
|
|
# Just continue.
|
|
break
|
|
fi
|
|
|
|
# Exit with error.
|
|
collect_output
|
|
exit 1
|
|
fi
|
|
|
|
sleep 0.01
|
|
done
|
|
|
|
trap - EXIT
|
|
|
|
# All terminated either by themselves, or with a benign timeout.
|
|
|
|
collect_output
|
|
|
|
# See if any returned an error.
|
|
result=0
|
|
for p in $procs; do
|
|
if [ -e "$p/.timeout" ]; then
|
|
# we're here because timeouts are ok, so don't mind the exit code
|
|
# if we initiated killing the process due to timeout
|
|
continue
|
|
fi
|
|
rc=$(cat "$p/.exitcode")
|
|
pid=$(cat "$p/.pid")
|
|
cmdline=$(cat "$p/.cmdline")
|
|
|
|
if [ "$rc" != 0 ]; then
|
|
echo ">>> process $pid failed with exitcode $rc: $cmdline" >>.stderr
|
|
result=1
|
|
fi
|
|
done
|
|
|
|
exit $result
|