[PATCH v2 4/6] add rlWaitForCmd

Hubert Kario hkario at redhat.com
Wed Nov 20 19:04:12 UTC 2013


add routine that allows waiting for any command to return
specified exit code

Signed-off-by: Hubert Kario <hkario at redhat.com>
---
 src/synchronisation.sh | 185 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 184 insertions(+), 1 deletion(-)

diff --git a/src/synchronisation.sh b/src/synchronisation.sh
index e782481..2885058 100644
--- a/src/synchronisation.sh
+++ b/src/synchronisation.sh
@@ -57,6 +57,136 @@ __INTERNAL_killtree() {
     return ${_ret:-0}
 }
 
+# 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() {
+
+    # don't wait more than this many seconds
+    local timeout=120
+    # delay between command invocations
+    local delay=1
+    # abort if this process terminates
+    local proc_pid=1
+    # command to run
+    local cmd
+    # maximum number of command invocations
+    local max_invoc=""
+    # expected return code of command
+    local exp_retval=0
+    # name of routine to return errors for
+    local routine_name="$1"
+    shift 1
+
+    # that is the GNU extended getopt syntax!
+    local TEMP=$(getopt -o t:p:m:d:r: -n '$routine_name' -- "$@")
+    if [[ $? != 0 ]] ; then
+        rlLogError "$routine_name: Can't parse command options, terminating..."
+        return 127
+    fi
+
+    eval set -- "$TEMP"
+
+    while true ; do
+        case "$1" in
+            -t) timeout="$2"; shift 2
+                ;;
+            -p) proc_pid="$2"; shift 2
+                ;;
+            -m) max_invoc="$2"; shift 2
+                ;;
+            -d) delay="$2"; shift 2
+                ;;
+            -r) exp_retval="$2"; shift 2
+                ;;
+            --) shift 1
+                break
+                ;;
+            *) rlLogError "$routine_name: unrecognized option"
+                return 127
+                ;;
+        esac
+    done
+    cmd="$1"
+
+    if [[ $routine_name == "rlWaitForCmd" ]]; then
+        rlLogInfo "$routine_name: waiting for \`$cmd' to return $exp_retval in $timeout seconds"
+    fi
+
+    # the case statement is a portable way to check if variable contains only
+    # digits (regexps are not available in old, RHEL3-era, bash)
+    case "$timeout" in
+        ''|*[!0-9]*) rlLogError "${routine_name}: Invalid timeout provided"
+            return 127
+            ;;
+    esac
+    case "$proc_pid" in
+        ''|*[!0-9]*) rlLogError "${routine_name}: Invalid PID provided"
+            return 127
+            ;;
+    esac
+    if [[ -n "$max_invoc" ]]; then
+        case "$max_invoc" in
+            ''|*[!0-9]*) rlLogError "${routine_name}: Invalid maximum number of invocations provided"
+                return 127
+                ;;
+        esac
+    fi
+    # delay can be fractional, so "." is OK
+    case "$delay" in
+        ''|*[!0-9.]*) rlLogError "${routine_name}: Invalid delay specified"
+            return 127
+            ;;
+    esac
+    case "$exp_retval" in
+        ''|*[!0-9]*) rlLogError "${routine_name}: Invalid expected command return value provided"
+            return 127
+            ;;
+    esac
+
+    # we use two child processes to get the timeout and process execution
+    # one (command_pid) runs the command until it returns expected return value
+    # the other is just a timout (watcher)
+
+    # run command in loop
+    ( local i=0
+    while [[ -n $max_invoc && $i -lt $max_invoc ]] || [[ ! -n $max_invoc ]]; do
+        eval $cmd
+        if [[ $? -eq $exp_retval ]]; then
+            exit 0;
+        else
+            if [[ ! -e "/proc/$proc_pid" ]]; then
+                exit 1;
+            fi
+            sleep $delay
+        fi
+        i=$((i+1))
+    done
+    exit 1) &
+    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
+    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
+        if [[ $ret -eq 1 ]]; then
+            __INTERNAL_killtree $watcher SIGKILL 2>/dev/null
+            wait $watcher 2> /dev/null
+            rlLogWarning "${routine_name}: PID terminated!"
+        else
+            rlLogWarning "${routine_name}: Timeout elapsed"
+        fi
+        return 1
+    fi
+}
+
 : <<'=cut'
 =pod
 
@@ -74,13 +204,66 @@ of applications.
 =cut
 
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-# rlWaitForSocket
+# rlWaitForCmd
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
 : <<'=cut'
 =pod
 
 =head2 Process Synchronisation
 
+=head3 rlWaitForCmd
+
+Pauses script execution until command exit status is the expeced value.
+Logs a WARNING and returns 1 if the command didn't exit successfully
+before timeout elapsed or a maximum number of invocations has been
+reached.
+
+    rlWaitForCmd command [-p PID] [-t time] [-n count] [-d delay] [-r retval]
+
+=over
+
+=item command
+
+Command that will be executed until its return code is equal 0 or value
+speciefied as option to `-r'.
+
+=item -t time
+
+Timeout in seconds, default=120. If the command doesn't return 0
+before time elapses, the command will be killed.
+
+=item -p PID
+
+PID of the process to check before running command. If the process
+exits before the socket is opened, the command will log a WARNING.
+
+=item -m count
+
+Maximum number of `command' executions before continuing anyway. Default is
+infite.
+
+=item -d delay
+
+Delay between `command' invocations. Default 1.
+
+=item -r retval
+
+Expected return value of command. Default 0.
+
+=back
+
+=cut
+rlWaitForCmd() {
+    __INTERNAL_wait_for_cmd rlWaitForCmd "$@"
+}
+
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# rlWaitForSocket
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+: <<'=cut'
+=pod
+
 =head3 rlWaitForSocket
 
 Pauses script execution until socket starts listening.
-- 
1.8.3.1



More information about the beakerlib-devel mailing list