diff options
-rw-r--r-- | functions.sh | 44 | ||||
-rwxr-xr-x | test-functions | 21 |
2 files changed, 64 insertions, 1 deletions
diff --git a/functions.sh b/functions.sh index 60a4b2e..e849541 100644 --- a/functions.sh +++ b/functions.sh @@ -496,6 +496,50 @@ oldest() } # +# Executes a simple command in parallel. At least two parameters are expected. +# The first parameter shall be taken as the maximum number of jobs to run +# concurrently. If specified as less than or equal to 0, the number shall be +# determined by running the nproc function. The second parameter shall be taken +# as a command name. The remaining parameters shall be conveyed to the specified +# command, one at a time. Should at least one command fail, the return value +# shall be greater than 0. +# +parallel_run() +{ + local arg cmd i statedir w workers + + if [ "$#" -lt 3 ]; then + warn "parallel_run: too few arguments (got $#, expected at least 3)" + return 1 + elif ! is_int "$1"; then + _warn_for_args parallel_run "$1" + return 1 + elif [ "$1" -le 0 ] && ! workers=$(get_nprocs); then + return 1 + elif ! statedir=${TMPDIR:-/tmp}/parallel_run.$$.$(srandom); then + return 1 + fi + workers=${workers:-$1} cmd=$2 + shift 2 + w=0 + i=0 + ( + while [ "$(( w += 1 ))" -le "${workers}" ]; do + i=$w + while [ "$i" -le "$#" ]; do + eval "arg=\$${i}" + if ! "${cmd}" "${arg}"; then + mkdir -p -- "${statedir}" + fi + i=$(( i + workers )) + done & + done + wait + ) + ! rmdir -- "${statedir}" 2>/dev/null +} + +# # Declare the vebegin, veerror, veindent, veinfo, veinfon, veoutdent and vewarn # functions. These differ from their non-v-prefixed counterparts in that they # only have an effect where EINFO_VERBOSE is true. diff --git a/test-functions b/test-functions index c734141..ed3da42 100755 --- a/test-functions +++ b/test-functions @@ -556,6 +556,25 @@ test_get_nprocs() { iterate_tests 2 "$@" } +test_parallel_run() { + set -- \ + ge 1 N/A N/A \ + eq 0 / N/A \ + ge 1 /var/empty/nonexistent N/A \ + eq 0 / / \ + ge 1 / /var/empty/nonexistent \ + ge 1 /var/empty/nonexistent /var/empty/nonexistent \ + ge 1 /var/empty/nonexistent / + + callback() { + shift + test_description="parallel_run $(_print_args 0 ls "$@")" + parallel_run 0 ls "$@" >/dev/null 2>&1 + } + + iterate_tests 4 "$@" +} + iterate_tests() { slice_width=$1 shift @@ -621,7 +640,7 @@ test_newest || rc=1 test_trim || rc=1 test_hr || rc=1 test_whenceforth || rc=1 -test_get_nprocs || rc=1 +test_parallel_run || rc=1 cleanup_tmpdir |