Hi all,
during work to make few tests use the new synchronise functions,
I've noticed that I'm re-using the same piece od code in few places.
So, reduce it, I'm intorducing rlWait, used just like bash 'wait'
but with ability to specify timeout and the signal used to kill
the command we are waiting for. Since I want the return value of
the background task, rlWatchdog didn't really cut it...
Needs to be applied on top of the synchronisation.sh patches.
Hubert Kario (1):
add rlWait
src/synchronisation.sh | 95 +++++++++++++++++++++++++++++++++++------
src/test/synchronisationTest.sh | 57 +++++++++++++++++++++++++
2 files changed, 140 insertions(+), 12 deletions(-)
--
1.8.3.1
Show replies by date
since the bash builtin `wait' command does not provide any kind of
timeout, we need to wrap it around a method that will allow
for killing the process we wait for
this does not duplicate functionality of rlWatchdog, as it does
use wait builtin and returns the background command exit code
allows to remove some code duplication in __INTERNAL_wait_for_cmd()
Signed-off-by: Hubert Kario <hkario(a)redhat.com>
---
src/synchronisation.sh | 95 +++++++++++++++++++++++++++++++++++------
src/test/synchronisationTest.sh | 57 +++++++++++++++++++++++++
2 files changed, 140 insertions(+), 12 deletions(-)
diff --git a/src/synchronisation.sh b/src/synchronisation.sh
index 9320b8c..d29affd 100644
--- a/src/synchronisation.sh
+++ b/src/synchronisation.sh
@@ -57,6 +57,40 @@ __INTERNAL_killtree() {
return ${_ret:-0}
}
+# wrapper around bash builtin `wait', adds timeout capability
+__INTERNAL_wait() {
+ local timeout=30
+ local sigspec=SIGTERM
+
+ while true ; do
+ case "$1" in
+ -t) timeout="$2"; shift 2
+ ;;
+ -s) sigspec="$2"; shift 2
+ ;;
+ --) shift 1
+ break;
+ ;;
+ *) rlLogError "rlWait: unrecognized option"
+ return 128
+ ;;
+ esac
+ done
+
+ local pids="$@"
+
+ (sleep $timeout && for pid in $pids; do __INTERNAL_killtree $pid
"$sigspec"; done)&
+ local watcher=$!
+ disown $watcher
+
+ wait "$@"
+ local my_ret=$?
+
+ __INTERNAL_killtree $watcher SIGKILL 2> /dev/null
+
+ return $my_ret
+}
+
# Since all "wait for something to happen" utilities are basically the same,
# use a generic routine that can do all their work
__INTERNAL_wait_for_cmd() {
@@ -165,34 +199,23 @@ __INTERNAL_wait_for_cmd() {
local command_pid=$!
# kill command running in background if the timout has elapsed
- ( sleep $timeout && __INTERNAL_killtree $command_pid SIGKILL) 2>/dev/null
&
- local watcher=$!
-
- wait $command_pid 2> /dev/null
+ __INTERNAL_wait -t $timeout -s SIGKILL -- $command_pid 2> /dev/null
local ret=$?
if [[ $ret -eq 0 ]]; then
- __INTERNAL_killtree $watcher SIGKILL 2>/dev/null
- wait $watcher 2> /dev/null
rlLogInfo "${routine_name}: Wait successful!"
return 0
else
case $ret in
1)
- __INTERNAL_killtree $watcher SIGKILL 2>/dev/null
- wait $watcher 2> /dev/null
rlLogWarning "${routine_name}: specified PID was terminated!"
;;
2)
- __INTERNAL_killtree $watcher SIGKILL 2>/dev/null
- wait $watcher 2> /dev/null
rlLogWarning "${routine_name}: Max number of test command
invocations reached!"
;;
143|137)
rlLogWarning "${routine_name}: Timeout reached"
;;
*)
- __INTERNAL_killtree $watcher SIGKILL 2>/dev/null
- wait $watcher 2> /dev/null
rlLogError "${routine_name}: Unknown termination cause! Return code:
$ret"
esac
return 1
@@ -445,6 +468,54 @@ rlWaitForSocket(){
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# rlWait
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+: <<'=cut'
+=pod
+
+=head3 rlWait
+
+Wrapper around bash builtin `wait' command. See bash_builtins(1) man page.
+Kills the process and all its children if the timeout elapses.
+
+ rlWaitFor [n ...] [-s SIGNAL] [-t time]
+
+=over
+
+=item n
+
+List of PIDs to wait for. They need to be background tasks of current shell.
+See bash_builtins(1) section for `wait' command/
+
+=item -t time
+
+Timeout in seconds (optional, default=30). If the wait isn't successful
+before the time elapses then all specified tasks are killed.
+
+=item -s SIGNAL
+
+Signal used to kill the process, optional SIGTERM by default.
+
+=back
+
+=cut
+
+rlWait() {
+ # that is the GNU extended getopt syntax!
+ local TEMP=$(getopt -o t:s: -n 'rlWait' -- "$@")
+ if [[ $? != 0 ]]; then
+ rlLogError "rlWait: Can't parse command options, terminating..."
+ return 128
+ fi
+
+ eval set -- "$TEMP"
+
+ __INTERNAL_wait "$@"
+
+ return $?
+}
+
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# AUTHORS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: <<'=cut'
diff --git a/src/test/synchronisationTest.sh b/src/test/synchronisationTest.sh
index ddbca1c..a7d81ca 100644
--- a/src/test/synchronisationTest.sh
+++ b/src/test/synchronisationTest.sh
@@ -236,3 +236,60 @@ test_rlWaitForCmdDelay() {
rm -rf $test_dir
}
+
+test_rlWaitPositive() {
+ local test_dir=$(mktemp -d /tmp/beakerlib-test-XXXXXX)
+
+ (sleep 4; touch ${test_dir}/file; exit 4)&
+
+ rlWait $!
+ ret=$?
+
+ assertTrue "Check if background task executed correctly" "[[ -e
${test_dir}/file ]]"
+ assertTrue "Check if returned value comes from background task" "[[
$ret -eq 4 ]]"
+
+ rm -rf $test_dir
+}
+
+test_rlWaitNoPIDs() {
+ local test_dir=$(mktemp -d /tmp/beakerlib-test-XXXXXX)
+
+ (sleep 4; touch ${test_dir}/file; exit 4)&
+
+ rlWait
+ ret=$?
+
+ assertTrue "Check if background task executed correctly" "[[ -e
${test_dir}/file ]]"
+ # when you `wait' for all tasks (no id specified), then wait always returns 0
+ assertTrue "Check if returned value is correct" "[[ $ret -eq 0
]]"
+
+ rm -rf $test_dir
+}
+
+test_rlWaitNegative() {
+ local test_dir=$(mktemp -d /tmp/beakerlib-test-XXXXXX)
+
+ (sleep 20; touch ${test_dir}/file; exit 4)&
+
+ rlWait $! -t 1
+ ret=$?
+
+ assertTrue "Check if background task didn't execute" "[[ ! -e
${test_dir}/file ]]"
+ assertTrue "Check if returned value indicates the task was killed" "[[
$ret -eq $((128+15)) ]]"
+
+ rm -rf $test_dir
+}
+
+test_rlWaitKill() {
+ local test_dir=$(mktemp -d /tmp/beakerlib-test-XXXXXX)
+
+ (sleep 20; touch ${test_dir}/file; exit 4)&
+
+ rlWait $! -t 1 -s SIGKILL
+ ret=$?
+
+ assertTrue "Check if background task didn't execute" "[[ ! -e
${test_dir}/file ]]"
+ assertTrue "Check if returned value indicates the task was killed by custom
signal" "[[ $ret -eq $((128+9)) ]]"
+
+ rm -rf $test_dir
+}
--
1.8.3.1