btest-bg-wait 2.97 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
#! /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

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 -a -s .timeout ]; then
        echo "The following processes did not terminate:" >>.stderr
        echo >>.stderr

        cat .timeout >>.stderr

        echo >>.stderr
        echo "-----------" >>.stderr
    fi

    for p in $procs; do
        pid=`cat $p/.pid`
        cmdline=`cat $p/.cmdline`

        printf "<<< [%s] %s\\n" "$pid" "$cmdline" >> .stdout
        cat $p/.stdout >>.stdout
        echo ">>>" >>.stdout

        printf "<<< [%s] %s\\n" "$pid" "$cmdline" >> .stderr
        cat $p/.stderr >>.stderr
        echo ">>>" >>.stderr
    done
}

trap kill_procs EXIT

while true; do

    if check_procs; then
        # All done.
        break
    fi

    timeout=`expr $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 1
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