123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999 |
- #!/bin/bash
- # Copyright (c) International Business Machines Corp., 2008
- # Author: Matt Helsley <matthltc@us.ibm.com>
- #
- # This library is free software; you can redistribute it and/or
- # modify it under the terms of the GNU Lesser General Public
- # License as published by the Free Software Foundation; either
- # version 2.1 of the License, or (at your option) any later version.
- #
- # This library is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- # Lesser General Public License for more details.
- #
- # You should have received a copy of the GNU Lesser General Public
- # License along with this library; if not, write to the Free Software
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- #
- #
- # A library of cgroup test functions for testing the cgroup freezer and,
- # if present, a cgroup signal subsystem.
- #
- # Most of these assume the current directory is the cgroup of interest.
- # mount_{freezer|signal} and make_sample_cgroup are the exceptions to this rule.
- #
- # On failure, a message indicating what failed is printed and the
- # exit status of the failing command is returned. If "result" is unset
- # then we assign the exit status of the failed command to it.
- #
- # The variable "result" holds the exit status of the first command that failed,
- # $UNFINISHED if no command has failed yet, or $FINISHED if no command
- # has failed and we've finished all significant parts of the test. Note:
- # significant parts usually do not include the cleanup of the test.
- #
- # xargs 4.1.20 only accepts -i instead of -I
- # However -I is added and -i deprecated somewhere between (4.1.20, 4.2.32]
- XRGSV=$(xargs --version | sed -e 's/^[^[:digit:]]*//')
- export XARGS_REPL_STR="%"
- case ${XRGSV} in
- [456789].[23456789][0-9]*.*|[1-9][0-9][0-9]*.*.*) # version > 4.1.*
- export XARGS_REPL_OPT="-I${XARGS_REPL_STR}"
- ;;
- 4.1.*|*)
- export XARGS_REPL_OPT="-i${XARGS_REPL_STR}"
- ;;
- esac
- unset XRGSV
- export UNFINISHED=""
- export FINISHED=0
- export TMP=${TMP:-/tmp}
- #
- # Tests are either running or cleaning up. Cleanup phases do not emit TFAIL.
- #
- export LIB_TEST_STATE="running"
- export max_state_samples=5 # number of times to sample
- export sample_state_period=1 # number of seconds between samplings
- export sample_sleep=5 # how long the sample program should sleep
- export result="$UNFINISHED"
- # These are echo'd to freezer.state.
- export FREEZE='FROZEN'
- export THAW='THAWED'
- # We use /bin/echo to write to cgroup files because it's exit status will not
- # hide write errors (bash's echo does not indicate if the write succeeded).
- export CG_FILE_WRITE=/bin/echo
- declare -r UNFINISHED FINISHED FREEZE THAW max_state_samples sample_state_period
- # When we're running we want to issue failure results when things go wrong.
- function running_cgroup_test()
- {
- export LIB_TEST_STATE="TFAIL"
- }
- # But when we're cleaning up we want to issue warnings (if not TINFO).
- function cleanup_cgroup_test()
- {
- export LIB_TEST_STATE="TWARN"
- }
- # Mounts the cgroup filesystem somewhere and pushes pwd onto the dir stack
- function mount_cgroup_subsys()
- {
- local rc=0
- mkdir -p $TMP/${cgroup_subsys}_test > /dev/null 2>&1
- rc=$?
- # Don't test status because we don't care if the directory already
- # exists.
- if [ ! -d $TMP/${cgroup_subsys}_test ]; then
- result=${result:-$rc}
- tst_brkm TBROK "Failed to make mount point for cgroup filesystem"
- return $result
- fi
- mount -t cgroup -o${cgroup_subsys} test_cgroup_${cgroup_subsys} $TMP/${cgroup_subsys}_test
- rc=$?
- if [ $rc -ne 0 ]; then
- result=${result:-$rc}
- tst_resm TINFO "Failed to mount cgroup filesystem with ${cgroup_subsys} subsystem."
- rmdir $TMP/${cgroup_subsys}_test 2> /dev/null
- return $rc
- fi
- export mount_cgroup_freezer_saved_dir="$(pwd)"
- cd $TMP/${cgroup_subsys}_test > /dev/null 2>&1
- rc=$?
- if [ $rc -ne 0 ]; then
- result=${result:-$rc}
- tst_brkm TBROK "Failed to change working directory into cgroup filesystem (pwd: \"$(pwd)\")"
- umount $TMP/${cgroup_subsys}_test || umount -l $TMP/${cgroup_subsys}_test || tst_brkm TBROK "Failed to unmount cgroup filesystem with ${cgroup_subsys} subsystem"
- rmdir $TMP/${cgroup_subsys}_test 2> /dev/null
- return $rc
- fi
- return 0
- }
- function mount_freezer()
- {
- export cgroup_subsys=freezer
- mount_cgroup_subsys
- }
- function mount_signal()
- {
- export cgroup_subsys=signal
- mount_cgroup_subsys
- }
- # umounts the cgroup filesystem and pops the dir stack
- function umount_cgroup_subsys()
- {
- cd "${mount_cgroup_freezer_saved_dir}"
- local cwd_result=$?
- umount $TMP/${cgroup_subsys}_test > /dev/null 2>&1 \
- || umount -l $TMP/${cgroup_subsys}_test || \
- tst_brkm TBROK "Failed to unmount cgroup filesystem (umount exit status: $?)"
- local umnt_result=$?
- local rc=0
- if [ $cwd_result -ne 0 ]; then
- result=${result:-$cwd_result}
- rc=$cwd_result
- elif [ $umnt_result -ne 0 ]; then
- result=${result:-$umnt_result}
- rc=$umnt_result
- elif [ $umnt_result -eq 0 -a $cwd_result -eq 0 ]; then
- rmdir $TMP/${cgroup_subsys}_test
- return 0
- fi
- return $rc
- }
- function umount_freezer()
- {
- [ "${cgroup_subsys}" != "freezer" ] && {
- result=${result:-5}
- exit -1
- }
- umount_cgroup_subsys
- unset cgroup_subsys
- }
- function cleanup_freezer()
- {
- local save_result="${result}"
- local save_pwd="$(pwd)"
- mount_freezer && {
- # Run these commands in bash because we need $(cmd subst) and
- # we need to redirect to different freezer.state files for each
- # group
- # Kill any leftover tasks
- disown -a
- find $TMP/${cgroup_subsys}_test -mindepth 1 -depth -type d -print0 | \
- xargs -0r -n 1 ${XARGS_REPL_OPT} /bin/bash -c 'kill $(cat "'"${XARGS_REPL_STR}"'/tasks") 2> /dev/null'
- # For each group in the freezer hierarch, that its tasks
- find $TMP/${cgroup_subsys}_test -mindepth 1 -depth -type d -print0 | \
- xargs -0r -n 1 ${XARGS_REPL_OPT} /bin/bash -c "\"${CG_FILE_WRITE}\" \"${THAW}\" > '${XARGS_REPL_STR}/freezer.state'"
- # Kill any leftover tasks
- find $TMP/${cgroup_subsys}_test -mindepth 1 -depth -type d -print0 | \
- xargs -0r -n 1 ${XARGS_REPL_OPT} /bin/bash -c 'kill $(cat "'"${XARGS_REPL_STR}"'/tasks") 2> /dev/null'
- sleep 2
- # Really kill any leftover tasks
- find $TMP/${cgroup_subsys}_test -mindepth 1 -depth -type d -print0 | \
- xargs -0r -n 1 ${XARGS_REPL_OPT} /bin/bash -c 'kill -s SIGKILL $(cat "'"${XARGS_REPL_STR}"'/tasks") 2> /dev/null'
- # Don't need to run these xargs commands in bash since we want
- # to see what's left on stdout
- LINES=$(find $TMP/${cgroup_subsys}_test -mindepth 1 -depth -type d -print0 | \
- xargs -0r -n 1 ${XARGS_REPL_OPT} cat "${XARGS_REPL_STR}/tasks" | wc -l)
- if (( LINES == 0 )); then
- # Remove the empty groups
- find $TMP/${cgroup_subsys}_test -mindepth 1 -depth -type d -print0 | xargs -r0 rmdir
- else
- tst_resm TWARN "Could not cleanup:"
- find $TMP/${cgroup_subsys}_test -mindepth 1 -depth -type d -print0 | xargs -0r -n 1 ${XARGS_REPL_OPT} ls -ld "${XARGS_REPL_STR}/tasks"
- fi
- umount_freezer
- }
- if [ "$save_pwd" != `pwd` ]; then
- tst_resm TWARN "libcgroup_subsys: cleanup_freezer() is broken"
- cd "$save_pwd"
- fi
- result="${save_result}"
- }
- function umount_signal()
- {
- [ "${cgroup_subsys}" != "signal" ] && {
- result=${result:-6}
- exit -1
- }
- umount_cgroup_subsys
- unset cgroup_subsys
- }
- function cleanup_signal()
- {
- local save_result="${result}"
- local save_pwd="$(pwd)"
- mount_signal && {
- find $TMP/${cgroup_subsys}_test -mindepth 1 -depth -type d -print0 | xargs -r0 rmdir
- umount_signal
- }
- if [ "$save_pwd" != `pwd` ]; then
- tst_resm TWARN "libcgroup_subsys: cleanup_signal() is broken"
- cd "$save_pwd"
- fi
- result="${save_result}"
- }
- function assert_cgroup_rwfile()
- {
- local file="$1"
- local descr="$2"
- local rc=0
- if [ ! -e "${file}" ]; then
- tst_resm ${LIB_TEST_STATE} "$descr missing"
- rc=1
- fi
- if [ ! -f "${file}" ]; then
- tst_resm ${LIB_TEST_STATE} "$descr is not a regular file"
- rc=2
- fi
- if [ ! -r "${file}" ]; then
- tst_resm ${LIB_TEST_STATE} "$descr is not readable"
- rc=3
- fi
- if [ ! -w "${file}" ]; then
- tst_resm ${LIB_TEST_STATE} "$descr is not writeable"
- rc=4
- fi
- [ $rc -ne 0 ] && {
- result=${result:-$rc}
- local s="$(stat "${file}")"
- tst_resm ${LIB_TEST_STATE} "${s}"
- }
- return $rc
- }
- function assert_cgroup_tasks_rwfile()
- {
- assert_cgroup_rwfile "tasks" "task list"
- return $?
- }
- function dump_named_cgroup_tasks()
- {
- local cgroup_name="$1"
- local tasks
- tasks=( $(cat "${cgroup_name}/tasks") ) # don't assign directly (bash bug)
- if [ -z "${tasks[*]}" ]; then
- return 0
- fi
- ps -p "${tasks[*]}" -o 'pid,ppid,pgid,tid,tpgid,blocked,ignored,pending,stat,tty,args'
- }
- function dump_cgroup_tasks()
- {
- dump_named_cgroup_tasks "$(pwd)"
- }
- function assert_cgroup_tasks_empty()
- {
- local nlines=$(( `cat tasks | wc -l` + 0))
- local rc=$?
- [ $rc -eq 0 -a $nlines -eq 0 ] && return 0
- rc=$?
- result=${result:-$rc}
- tst_resm ${LIB_TEST_STATE} "cgroup task list is not empty: "
- dump_cgroup_tasks 1>&2
- return $rc
- }
- function assert_task_in_named_cgroup()
- {
- local task_pid=$1
- local cgroup_name="$2"
- cat "${cgroup_name}/tasks" | grep -E "^${task_pid}\$" > /dev/null 2>&1 && return 0
- local rc=$?
- result=${result:-$rc}
- tst_resm ${LIB_TEST_STATE} "Expected pid ${task_pid} is not in \"${cgroup_name}\" task list"
- dump_named_cgroup_tasks "${cgroup_name}" 1>&2
- return $rc
- }
- function assert_task_not_in_named_cgroup()
- {
- local task_pid=$1
- local cgroup_name="$2"
- cat "${cgroup_name}/tasks" | grep -E "^${task_pid}\$" > /dev/null 2>&1 || return 0
- local rc=1 # $? == 0 is an error in this case
- result=${result:-$rc}
- tst_resm ${LIB_TEST_STATE} "Expected pid ${task_pid} is in \"${cgroup_name}\" task list"
- dump_named_cgroup_tasks "${cgroup_name}" 1>&2
- return $rc
- }
- function assert_task_in_cgroup()
- {
- assert_task_in_named_cgroup $1 "$(pwd)"
- return $?
- }
- function assert_task_not_in_cgroup()
- {
- assert_task_not_in_named_cgroup $1 "$(pwd)"
- return $?
- }
- function assert_sample_proc_in_cgroup()
- {
- assert_task_in_cgroup $sample_proc
- return $?
- }
- function assert_sample_proc_not_in_cgroup()
- {
- assert_task_not_in_cgroup $sample_proc
- return $?
- }
- function assert_sample_proc_in_named_cgroup()
- {
- assert_task_in_named_cgroup $sample_proc "$1"
- return $?
- }
- function assert_sample_proc_not_in_named_cgroup()
- {
- assert_task_not_in_named_cgroup $sample_proc "$1"
- return $?
- }
- function get_task_state()
- {
- ps -p $1 -o 'state=' 2>/dev/null
- }
- # TODO Check: Do these need to ignore case differences?
- function assert_task_state()
- {
- local task_pid=$1
- local expected_state="$2"
- local ps_state="$(get_task_state ${task_pid})"
- local rc=$?
- [ $rc -eq 0 -a "$ps_state" == "${expected_state}" ] && return 0
- rc=$?
- result=${result:-$rc}
- tst_resm ${LIB_TEST_STATE} "Expected task ${task_pid} to be in state \"${expected_state}\""
- return $rc
- }
- #
- # Check that the specified task is not in the specified state
- #
- function assert_task_not_in_state()
- {
- local task_pid=$1
- local expected_state="$2"
- local ps_state="$(get_task_state ${task_pid})"
- local rc=$?
- [ $rc -eq 0 -a "$ps_state" != "${expected_state}" ] && return 0
- rc=$?
- result=${result:-$rc}
- tst_resm ${LIB_TEST_STATE} "Expected task ${task_pid} to not be in state \"${expected_state}\""
- return $rc
- }
- #
- # Frozen tasks are in the "D" state according to ps
- # tasks in "T" state may also be in a "frozen" state
- #
- function assert_task_not_frozen()
- {
- local task_pid=$1
- local ps_state="$(ps -p $task_pid -o 'state=')"
- local rc=$?
- [ $rc -eq 0 -a "$ps_state" != "D" ] && return 0
- rc=$?
- result=${result:-$rc}
- tst_resm ${LIB_TEST_STATE} "Expected task ${task_pid} is not frozen (unexpected task state: \"$ps_state\")"
- return $rc
- }
- function assert_task_is_frozen()
- {
- local task_pid=$1
- local ps_state="$(ps -p $task_pid -o 'state=')"
- local rc=$?
- [ $rc -eq 0 -a "$ps_state" == "D" -o "$ps_state" == "T" ] && return 0
- rc=$?
- result=${result:-$rc}
- tst_resm ${LIB_TEST_STATE} "Expected task ${task_pid} to be frozen (unexpected task state: \"$ps_state\")"
- return $rc
- }
- function assert_sample_proc_not_frozen()
- {
- assert_task_not_frozen $sample_proc
- return $?
- }
- function assert_sample_proc_is_frozen()
- {
- assert_task_is_frozen $sample_proc
- return $?
- }
- function assert_sample_proc_stopped()
- {
- assert_task_state $sample_proc 'T'
- return $?
- }
- function assert_sample_proc_not_stopped()
- {
- assert_task_not_in_state $sample_proc 'T'
- return $?
- }
- function assert_sample_proc_sleeping()
- {
- assert_task_state $sample_proc 'S'
- return $?
- }
- function assert_sample_proc_not_sleeping()
- {
- assert_task_not_in_state $sample_proc 'S'
- return $?
- }
- function assert_cgroup_subsys_state_rwfile()
- {
- if [ "${cgroup_subsys}" == "freezer" ]; then
- assert_cgroup_rwfile "freezer.state" "freezer state"
- return $?
- elif [ "${cgroup_subsys}" == "freezer" ]; then
- assert_cgroup_rwfile "signal.kill" "signal file"
- return $?
- else
- return -1
- fi
- }
- function get_freezer_state()
- {
- local state="$(cat freezer.state)"
- local rc=$?
- if [ $rc -ne 0 ]; then
- result=${result:-$rc}
- tst_resm ${LIB_TEST_STATE} "Failed to read freezer state."
- return $rc
- fi
- echo "${state}"
- return 0
- }
- function assert_cgroup_freezer_state()
- {
- local goal_state="$1"
- local state="$(get_freezer_state)"
- local rc=$?
- [ $rc -eq 0 -a "${state}" == "${goal_state}" ] && return 0
- rc=$?
- result=${result:-$rc}
- tst_resm ${LIB_TEST_STATE} "Expected freezer state \"$2\" but found freezer state: \"$state\""
- return $rc
- }
- function make_sample_cgroup_named()
- {
- local name="$1"
- local saved_dir="$(pwd)"
- mkdir "${name}"
- local rc=$?
- # So long as we made the directory we don't care
- if [ ! -d "${name}" -a $rc -ne 0 ]; then
- # But if it doesn't exist report the exit status of mkdir
- result=${result:-$rc}
- return $rc
- fi
- cd "${name}" > /dev/null 2>&1
- rc=$?
- if [ $rc -ne 0 ]; then
- result=${result:-$rc}
- return $rc
- fi
- assert_cgroup_tasks_rwfile || {
- cd "${saved_dir}"
- return $?
- }
- assert_cgroup_tasks_empty || {
- cd "${saved_dir}"
- return $?
- }
- assert_cgroup_subsys_state_rwfile || {
- cd "${saved_dir}"
- return $?
- }
- cd "${saved_dir}"
- return 0
- }
- function make_sample_cgroup()
- {
- make_sample_cgroup_named "child"
- local rc=$?
- # So long as we made the directory we don't care
- if [ $rc -ne 0 ]; then
- return $rc
- fi
- cd "child" # we know this will succeed since make_sample_cgroup_named
- # tested this
- return 0
- }
- function rm_sample_cgroup_named()
- {
- local cgroup_name="$1"
- local saved_dir="$(pwd)"
- local rc=0
- cd "${cgroup_name}" && {
- assert_cgroup_tasks_rwfile || {
- cd "${saved_dir}"
- return $?
- }
- assert_cgroup_tasks_empty || {
- cd "${saved_dir}"
- return $?
- }
- assert_cgroup_subsys_state_rwfile || {
- cd "${saved_dir}"
- return $?
- }
- cd "${saved_dir}"
- } || {
- rc=$?
- result=${result:-$rc}
- return $rc
- }
- [ -d "${cgroup_name}" ] && rmdir "${cgroup_name}" && return 0
- rc=$?
- tst_resm TWARN "Failed to remove cgroup \"${cgroup_name}\""
- result=${result:-$rc}
- return $rc
- }
- function rm_sample_cgroup()
- {
- local cgroup_name="$(basename $(pwd))"
- local rc=0
- cd .. || {
- rc=$?
- result=${result:-$rc}
- return $rc
- }
- rm_sample_cgroup_named "${cgroup_name}"
- return $?
- }
- function ls_pids()
- {
- ps -e -o 'pid=' | sed -e 's/[[:space:]]\+//g'
- }
- function assert_task_exists()
- {
- local task_pid=$1
- ls_pids | grep -E "^${task_pid}\$" > /dev/null 2>&1 && return 0
- local rc=$?
- result=${result:-$rc}
- tst_resm ${LIB_TEST_STATE} "Expected pid ${task_pid} does not exist"
- return $rc
- }
- function assert_task_does_not_exist()
- {
- local task_pid=$1
- ls_pids | grep -E "^${task_pid}\$" > /dev/null 2>&1 || return 0
- local rc=1 # $? == 0 is an error in this case
- result=${result:-$rc}
- tst_resm ${LIB_TEST_STATE} "Did not expect pid ${task_pid} to exist"
- return $rc
- }
- function assert_sample_proc_exists()
- {
- assert_task_exists $sample_proc
- return $?
- }
- function assert_sample_proc_does_not_exist()
- {
- assert_task_does_not_exist $sample_proc
- return $rc
- }
- function start_sample_proc()
- {
- local sample_cmd="/bin/sleep"
- local args
- args=( $sample_sleep ) # can't assign directly because of bash v2/v3 inconsistency
- if [ $# -gt 0 ]; then
- sample_cmd="$1"
- shift 1
- args=( "$@" )
- fi
- [ -n "$sample_proc" ] && assert_sample_proc_does_not_exist
- "$sample_cmd" "${args[@]}" &
- local rc=$?
- export sample_proc=$!
- assert_sample_proc_exists
- return $rc
- }
- function add_sample_proc_to_named_cgroup()
- {
- local cgroup_name="$1"
- assert_sample_proc_exists
- "${CG_FILE_WRITE}" $sample_proc > "${cgroup_name}/tasks"
- local rc=$?
- if [ $rc -ne 0 ]; then
- result=${result:-$rc}
- tst_resm ${LIB_TEST_STATE} "Failed to add sample process $sample_proc to cgroup \"${cgroup_name}\""
- return $rc
- fi
- assert_task_in_named_cgroup $sample_proc "${cgroup_name}"
- return $?
- }
- function add_sample_proc_to_cgroup()
- {
- add_sample_proc_to_named_cgroup "$(pwd)"
- return $?
- }
- function kill_sample_proc()
- {
- if [ -z "$sample_proc" ]; then
- # It's no longer running or never started.
- # If it was supposed to have started but did not then that
- # should be determined by checking start_sample_proc results.
- return 0
- fi
- # Hey, bash, don't print out any of your messy job status notices
- disown -a
- if [ "$(get_task_state $sample_proc)" == "D" ]; then
- tst_resm TWARN "sample process is frozen stiff"
- kill $sample_proc
- local rc=$?
- result=${result:-$rc}
- return $rc
- fi
- # kill child processes of the sample process
- while pgrep -P $sample_proc ; do
- pkill -SIGTERM -P $sample_proc
- sleep 1
- pkill -SIGKILL -P $sample_proc
- ps -p $(pgrep -P $sample_proc) -o 'state=' | grep -v D && continue
- # Give up if all the child processes are frozen in D state or
- # if there aren't any more child processes
- break
- done
- # DEBUG dump pstree under $sample_proc:
- # pstree -A -p $sample_proc
- kill $sample_proc > /dev/null 2>&1 || kill -s SIGKILL $sample_proc > /dev/null 2>&1 || {
- local rc=$?
- ps -p $sample_proc -o 'state=' > /dev/null 2>&1
- if [ $? -eq 1 ]; then
- # It's dead. We're OK.
- return 0
- fi
- # It's still alive somehow! Give up.
- result=${result:-$rc}
- tst_resm TWARN "Failed to kill sample process $sample_proc (kill exit status: $rc)"
- }
- assert_sample_proc_not_in_cgroup
- assert_sample_proc_does_not_exist
- return $?
- }
- function issue_freeze_cmd()
- {
- local goal_state="FROZEN"
- local sample_state_count=1
- local state="$(get_freezer_state)"
- local rc=$?
- if [ $rc -ne 0 ]; then
- return $rc
- fi
- while [ "${state}" != "${goal_state}" ]; do
- "${CG_FILE_WRITE}" "${FREEZE}" > freezer.state
- sleep $sample_state_period
- state="$(get_freezer_state)"
- rc=$?
- if [ $rc -ne 0 ]; then
- break
- fi
- ((sample_state_count++))
- if [ "$sample_state_count" -ge "$max_state_samples" ]; then
- break
- fi
- done
- if [ "${state}" == "${goal_state}" ]; then
- return 0
- fi
- result=${result:-$rc}
- tst_resm ${LIB_TEST_STATE} "Failed to issue freeze command (freezer state: \"`get_freezer_state`\")."
- return $rc
- }
- # If we're trying to "freeze" tasks with SIGTOP
- function issue_stop_as_freeze_cmd()
- {
- local goal_state="T"
- local sample_state_count=1
- local ps_state="$(get_task_state ${task_pid})"
- local rc=$?
- if [ $rc -ne 0 ]; then
- return $rc
- fi
- while [ "${ps_state}" != "${goal_state}" ]; do
- kill -s SIGSTOP $sample_proc
- sleep $sample_state_period
- ps_state="$(get_task_state ${task_pid})"
- rc=$?
- if [ $rc -ne 0 ]; then
- break
- fi
- ((sample_state_count++))
- if [ "$sample_state_count" -ge "$max_state_samples" ]; then
- break
- fi
- done
- if [ "${ps_state}" == "${goal_state}" ]; then
- return 0
- fi
- result=${result:-$rc}
- tst_resm ${LIB_TEST_STATE} "Failed to issue stop (freeze) command (task state: \"${ps_state}\")."
- return $rc
- }
- function send_signal()
- {
- "${CG_FILE_WRITE}" $1 > 'signal.kill' && return 0
- local rc=$?
- result=${result:-$rc}
- tst_resm ${LIB_TEST_STATE} "Failed to send signal: $1 to tasks in cgroup (rc: $rc)"
- return $rc
- }
- function wait_until_goal_state_or_timeout()
- {
- local goal_state="$1"
- local sample_state_count=1
- local state="$(get_freezer_state)"
- local rc=$?
- if [ $rc -ne 0 ]; then
- return $rc
- fi
- while [ "${state}" != "${goal_state}" ]; do
- sleep $sample_state_period
- state="$(get_freezer_state)"
- rc=$?
- if [ $rc -ne 0 ]; then
- break
- fi
- ((sample_state_count++))
- if [ "$sample_state_count" -ge "$max_state_samples" ]; then
- break
- fi
- done
- return $rc
- }
- # TODO convert signal scripts -- insert task between until and goal
- function wait_until_sample_proc_goal_state_or_timeout()
- {
- local goal_state="$1"
- local sample_state_count=1
- local ps_state="$(get_task_state ${sample_proc})"
- local rc=$?
- while [ $rc -eq 0 -a "${ps_state}" != "${goal_state}" -a \
- "$sample_state_count" -lt "$max_state_samples" ]; do
- sleep $sample_state_period
- ps_state="$(get_task_state ${sample_proc})"
- rc=$?
- if [ $rc -ne 0 ]; then
- result=${result:-$rc}
- tst_resm ${LIB_TEST_STATE} "Failed to read process state."
- break
- fi
- ((sample_state_count++))
- done
- return $rc
- }
- # TODO convert signal scripts -- insert task between until and not
- function wait_until_sample_proc_not_goal_state_or_timeout()
- {
- local goal_state="$1"
- local sample_state_count=1
- local ps_state="$(get_task_state ${sample_proc})"
- local rc=$?
- while [ $rc -eq 0 -a "${ps_state}" == "${goal_state}" -a \
- "$sample_state_count" -lt "$max_state_samples" ]; do
- sleep $sample_state_period
- ps_state="$(get_task_state ${sample_proc})"
- rc=$?
- if [ $rc -ne 0 ]; then
- result=${result:-$rc}
- tst_resm ${LIB_TEST_STATE} "Failed to read process state."
- break
- fi
- ((sample_state_count++))
- done
- return $rc
- }
- function wait_until_frozen()
- {
- wait_until_goal_state_or_timeout "FROZEN" || return $?
- assert_cgroup_freezer_state "FROZEN" "ERROR: failed to freeze cgroup"
- # TODO assert all tasks in cgroup are in 'D' or 'T' state
- # TODO assert that trying to add a task to cgroup results in EBUSY
- return $?
- }
- function issue_thaw_cmd()
- {
- "${CG_FILE_WRITE}" "${THAW}" > freezer.state && return 0
- local rc=$?
- result=${result:-$rc}
- tst_resm ${LIB_TEST_STATE} "Failed to issue thaw command."
- return $rc
- }
- function issue_cont_as_thaw_cmd()
- {
- local goal_state="T"
- local sample_state_count=1
- local ps_state="$(get_task_state ${task_pid})"
- local rc=$?
- if [ $rc -ne 0 ]; then
- return $rc
- fi
- while [ "${ps_state}" == "${goal_state}" ]; do
- kill -s SIGCONT $sample_proc
- sleep $sample_state_period
- ps_state="$(get_task_state ${task_pid})"
- rc=$?
- if [ $rc -ne 0 ]; then
- break
- fi
- ((sample_state_count++))
- if [ "$sample_state_count" -ge "$max_state_samples" ]; then
- break
- fi
- done
- if [ "${ps_state}" != "${goal_state}" ]; then
- return 0
- fi
- result=${result:-$rc}
- tst_resm ${LIB_TEST_STATE} "Failed to issue continue (thaw) command (task state: \"${ps_state}\")."
- return $rc
- }
- function wait_until_thawed()
- {
- wait_until_goal_state_or_timeout "THAWED" || return $?
- assert_cgroup_freezer_state "THAWED" "ERROR: Failed to thaw cgroup."
- return $?
- }
- function wait_until_freezing()
- {
- wait_until_goal_state_or_timeout "FREEZING"
- # Time critical -- we race with the kernel as it freezes tasks in the
- # cgroup. So rather than assert "FREEZING" we just return
- return $?
- }
- function wait_until_sample_proc_stopped()
- {
- wait_until_sample_proc_state_or_timeout 'T' || return $?
- assert_sample_proc_stopped
- return $?
- }
- function wait_until_sample_proc_not_stopped()
- {
- wait_until_sample_proc_not_goal_state_or_timeout 'T' || return $?
- assert_sample_proc_not_stopped
- return $?
- }
|