1
0

Compare commits

...

9 Commits

9 changed files with 265 additions and 0 deletions

54
all-full-example.sh Executable file
View File

@ -0,0 +1,54 @@
#!/bin/sh
set -e
# From https://stackoverflow.com/a/360275
kill_child_jobs() {
echo "In kill_child_jobs()..."
# Workaround for https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=482999
tmp="$(mktemp)"
jobs -p > "$tmp"
child_pids=$(cat "$tmp")
for child in $child_pids
do
# From https://unix.stackexchange.com/a/574169
if [ -n "${child##*[!0-9]*}" ]
then
echo Killing "$child"
# From https://stackoverflow.com/a/11231970
kill "$child" || true
fi
done
# zsh version from https://stackoverflow.com/a/36354483
# zsh doesn't have jobs -p
jobs > "$tmp"
cat "$tmp"
<"$tmp" sed --regexp-extended --quiet 's/\[([[:digit:]]+)\].*running.*/%\1/gp' | while read -r child
do
echo Killing job "$child"
kill "$child" || true
done
rm "$tmp"
}
cleanup() {
kill_child_jobs
}
#trap "kill_child_jobs" INT TERM QUIT
#trap date INT TERM QUIT
# From https://unix.stackexchange.com/a/240736
for sig in INT QUIT HUP TERM ALRM USR1; do
trap "
cleanup
trap - $sig EXIT
kill -s $sig "'"$$"' "$sig"
done
trap cleanup EXIT
yes aa &
yes b &
sleep 100 &
wait

33
all.sh Executable file
View File

@ -0,0 +1,33 @@
#!/bin/sh
set -e
# From https://stackoverflow.com/a/360275
kill_child_jobs() {
echo "In kill_child_jobs()..."
# Workaround for https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=482999
tmp="$(mktemp)"
jobs -p > "$tmp"
child_pids=$(cat "$tmp")
for child in $child_pids
do
# From https://unix.stackexchange.com/a/574169
if [ -n "${child##*[!0-9]*}" ]
then
echo Killing "$child"
# From https://stackoverflow.com/a/11231970
kill "$child" || true
fi
done
# zsh version from https://stackoverflow.com/a/36354483
# zsh doesn't have jobs -p
jobs > "$tmp"
cat "$tmp"
<"$tmp" sed --regexp-extended --quiet 's/\[([[:digit:]]+)\].*running.*/%\1/gp' | while read -r child
do
echo Killing job "$child"
kill "$child" || true
done
rm "$tmp"
}

4
noop.sh Executable file
View File

@ -0,0 +1,4 @@
kill_child_jobs() {
# Do nothing to show what test script does when jobs are not killed.
:
}

6
pkill-P.sh Executable file
View File

@ -0,0 +1,6 @@
kill_child_jobs() {
echo "In kill_child_jobs()..."
# From https://stackoverflow.com/a/23336595
# Kills all child proceses, not just jobs.
pkill -P $$
}

View File

@ -0,0 +1,16 @@
#!/bin/sh
set -e
DIR=$(dirname "$0")
. "$1"
# Set up child jobs
"$DIR/wait_for_pid_exit.sh" job $$ &
"$DIR/wait_for_pid_exit.sh" disowned $$ &
builtin disown || echo "shell does not support disown"
# Wait for jobs to actually start.
sleep 0.01s
kill_child_jobs

44
test/test-all.sh Executable file
View File

@ -0,0 +1,44 @@
#!/bin/sh
set -e
DIR="$(dirname "$0")"
SHELLS="bash sh ash dash zsh ksh"
echo "Legend:"
echo " ∞=script does not halt (after 1 second timeout)"
echo " X=disown unsupported by shell"
echo " ☠=all children killed"
echo " 🏃=all children still running"
echo
printf '\t'
for shell in $SHELLS
do
if ! command -v "$shell" >/dev/null
then
>&2 echo "Shell $shell not found."
exit 1
fi
printf '\t%s' "$shell"
done
printf '\n'
for script in "$DIR"/../*.sh
do
if [ -x "$script" ] && grep -qF 'kill_child_jobs()' "$script" && ! grep -qF 'wait' "$script"
then
name="$(basename "$script")"
printf '%s' "$name"
if [ ${#name} -lt 8 ]
then
printf '\t'
fi
for shell in $SHELLS
do
printf '\t'
"$DIR/test-kill-child-jobs.sh" "$script" "$shell" || true
done
fi
printf '\n'
done

72
test/test-kill-child-jobs.sh Executable file
View File

@ -0,0 +1,72 @@
#!/bin/sh
set -e
DIR="$(dirname "$0")"
SCRIPT="$1"
SHELL="$2"
if [ ! -x "$SCRIPT" ]
then
>&2 echo "First argument should be file with kill_child_jobs() function to test."
exit 1
fi
if ! command -v "$SHELL" >/dev/null
then
>&2 echo "Second argument should be shell to test."
exit 1
fi
TMP="$(mktemp)"
# timeout code from https://stackoverflow.com/a/10028986
pidFile="$(mktemp)"
(
"$SHELL" "$DIR/make-and-kill-child-jobs.sh" "$SCRIPT" >"$TMP" 2>&1 || true
rm "$pidFile"
) &
pid=$!
echo $pid > "$pidFile"
(
sleep 1
if [ -e "$pidFile" ]
then
pkill -P $pid
printf '∞'
fi
) &
killerPid=$!
wait $pid
kill $killerPid 2>/dev/null || true
rm -f "$pidFile" || true
# Make sure we've waited long enough for the "outlived" messages to be generated.
sleep 0.1s
if grep -q '^shell does not support disown$' "$TMP"
then
printf "X"
fi
if ! grep -q '^disowned outlived parent.$' "$TMP"
then
# disowned should have outlived parent
EXITCODE=2
printf "☠"
elif grep -q '^job outlived parent.$' "$TMP"
then
# job should not outlive parent
EXITCODE=3
printf "🏃"
else
# all good
EXITCODE=0
printf '%s' "$SHELL"
fi
rm -f "$TMP"
exit $EXITCODE

8
test/wait_for_pid_exit.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/sh
echo "Starting child $1..."
while kill -0 "$2" 2>/dev/null
do
sleep 0.01s
done
echo "$1 outlived parent."

28
zsh.sh Executable file
View File

@ -0,0 +1,28 @@
#!/bin/zsh
set -e
# From https://stackoverflow.com/a/360275
kill_child_jobs() {
echo "In kill_child_jobs()..."
# From https://unix.stackexchange.com/a/544167
while kill %% >/dev/null; do :; done
}
cleanup() {
kill_child_jobs
}
# From https://unix.stackexchange.com/a/240736
for sig in INT QUIT HUP TERM ALRM USR1; do
trap "
cleanup
trap - $sig EXIT
kill -s $sig "'"$$"' "$sig"
done
trap cleanup EXIT
yes aa &
yes b &
sleep 100 &
wait