1#!/bin/bash 2# Copyright (c) International Business Machines Corp., 2008 3# Author: Matt Helsley <matthltc@us.ibm.com> 4# 5# This library is free software; you can redistribute it and/or 6# modify it under the terms of the GNU Lesser General Public 7# License as published by the Free Software Foundation; either 8# version 2.1 of the License, or (at your option) any later version. 9# 10# This library is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13# Lesser General Public License for more details. 14# 15# You should have received a copy of the GNU Lesser General Public 16# License along with this library; if not, write to the Free Software 17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18# 19# 20 21# A library of cgroup test functions for testing the cgroup freezer and, 22# if present, a cgroup signal subsystem. 23# 24# Most of these assume the current directory is the cgroup of interest. 25# mount_{freezer|signal} and make_sample_cgroup are the exceptions to this rule. 26# 27# On failure, a message indicating what failed is printed and the 28# exit status of the failing command is returned. If "result" is unset 29# then we assign the exit status of the failed command to it. 30# 31# The variable "result" holds the exit status of the first command that failed, 32# $UNFINISHED if no command has failed yet, or $FINISHED if no command 33# has failed and we've finished all significant parts of the test. Note: 34# significant parts usually do not include the cleanup of the test. 35# 36 37 38# xargs 4.1.20 only accepts -i instead of -I 39# However -I is added and -i deprecated somewhere between (4.1.20, 4.2.32] 40XRGSV=$(xargs --version | sed -e 's/^[^[:digit:]]*//') 41export XARGS_REPL_STR="%" 42case ${XRGSV} in 43[456789].[23456789][0-9]*.*|[1-9][0-9][0-9]*.*.*) # version > 4.1.* 44 export XARGS_REPL_OPT="-I${XARGS_REPL_STR}" 45 ;; 464.1.*|*) 47 export XARGS_REPL_OPT="-i${XARGS_REPL_STR}" 48 ;; 49esac 50unset XRGSV 51 52export UNFINISHED="" 53export FINISHED=0 54export TMP=${TMP:-/tmp} 55 56# 57# Tests are either running or cleaning up. Cleanup phases do not emit TFAIL. 58# 59export LIB_TEST_STATE="running" 60 61export max_state_samples=5 # number of times to sample 62export sample_state_period=1 # number of seconds between samplings 63export sample_sleep=5 # how long the sample program should sleep 64export result="$UNFINISHED" 65 66# These are echo'd to freezer.state. 67export FREEZE='FROZEN' 68export THAW='THAWED' 69 70# We use /bin/echo to write to cgroup files because it's exit status will not 71# hide write errors (bash's echo does not indicate if the write succeeded). 72export CG_FILE_WRITE=/bin/echo 73 74declare -r UNFINISHED FINISHED FREEZE THAW max_state_samples sample_state_period 75 76# When we're running we want to issue failure results when things go wrong. 77function running_cgroup_test() 78{ 79 export LIB_TEST_STATE="TFAIL" 80} 81 82# But when we're cleaning up we want to issue warnings (if not TINFO). 83function cleanup_cgroup_test() 84{ 85 export LIB_TEST_STATE="TWARN" 86} 87 88# Mounts the cgroup filesystem somewhere and pushes pwd onto the dir stack 89function mount_cgroup_subsys() 90{ 91 local rc=0 92 93 mkdir -p $TMP/${cgroup_subsys}_test > /dev/null 2>&1 94 rc=$? 95 96 # Don't test status because we don't care if the directory already 97 # exists. 98 99 if [ ! -d $TMP/${cgroup_subsys}_test ]; then 100 result=${result:-$rc} 101 tst_brkm TBROK "Failed to make mount point for cgroup filesystem" 102 return $result 103 fi 104 105 mount -t cgroup -o${cgroup_subsys} test_cgroup_${cgroup_subsys} $TMP/${cgroup_subsys}_test 106 rc=$? 107 if [ $rc -ne 0 ]; then 108 result=${result:-$rc} 109 tst_resm TINFO "Failed to mount cgroup filesystem with ${cgroup_subsys} subsystem." 110 rmdir $TMP/${cgroup_subsys}_test 2> /dev/null 111 return $rc 112 fi 113 114 export mount_cgroup_freezer_saved_dir="$(pwd)" 115 cd $TMP/${cgroup_subsys}_test > /dev/null 2>&1 116 rc=$? 117 if [ $rc -ne 0 ]; then 118 result=${result:-$rc} 119 tst_brkm TBROK "Failed to change working directory into cgroup filesystem (pwd: \"$(pwd)\")" 120 umount $TMP/${cgroup_subsys}_test || umount -l $TMP/${cgroup_subsys}_test || tst_brkm TBROK "Failed to unmount cgroup filesystem with ${cgroup_subsys} subsystem" 121 rmdir $TMP/${cgroup_subsys}_test 2> /dev/null 122 return $rc 123 fi 124 125 return 0 126} 127 128function mount_freezer() 129{ 130 export cgroup_subsys=freezer 131 mount_cgroup_subsys 132} 133 134function mount_signal() 135{ 136 export cgroup_subsys=signal 137 mount_cgroup_subsys 138} 139 140# umounts the cgroup filesystem and pops the dir stack 141function umount_cgroup_subsys() 142{ 143 cd "${mount_cgroup_freezer_saved_dir}" 144 local cwd_result=$? 145 umount $TMP/${cgroup_subsys}_test > /dev/null 2>&1 \ 146 || umount -l $TMP/${cgroup_subsys}_test || \ 147 tst_brkm TBROK "Failed to unmount cgroup filesystem (umount exit status: $?)" 148 local umnt_result=$? 149 local rc=0 150 151 if [ $cwd_result -ne 0 ]; then 152 result=${result:-$cwd_result} 153 rc=$cwd_result 154 elif [ $umnt_result -ne 0 ]; then 155 result=${result:-$umnt_result} 156 rc=$umnt_result 157 elif [ $umnt_result -eq 0 -a $cwd_result -eq 0 ]; then 158 rmdir $TMP/${cgroup_subsys}_test 159 return 0 160 fi 161 162 return $rc 163} 164 165function umount_freezer() 166{ 167 [ "${cgroup_subsys}" != "freezer" ] && { 168 result=${result:-5} 169 exit -1 170 } 171 umount_cgroup_subsys 172 unset cgroup_subsys 173} 174 175function cleanup_freezer() 176{ 177 local save_result="${result}" 178 local save_pwd="$(pwd)" 179 180 mount_freezer && { 181 # Run these commands in bash because we need $(cmd subst) and 182 # we need to redirect to different freezer.state files for each 183 # group 184 # Kill any leftover tasks 185 disown -a 186 find $TMP/${cgroup_subsys}_test -mindepth 1 -depth -type d -print0 | \ 187 xargs -0r -n 1 ${XARGS_REPL_OPT} /bin/bash -c 'kill $(cat "'"${XARGS_REPL_STR}"'/tasks") 2> /dev/null' 188 189 # For each group in the freezer hierarch, that its tasks 190 find $TMP/${cgroup_subsys}_test -mindepth 1 -depth -type d -print0 | \ 191 xargs -0r -n 1 ${XARGS_REPL_OPT} /bin/bash -c "\"${CG_FILE_WRITE}\" \"${THAW}\" > '${XARGS_REPL_STR}/freezer.state'" 192 193 # Kill any leftover tasks 194 find $TMP/${cgroup_subsys}_test -mindepth 1 -depth -type d -print0 | \ 195 xargs -0r -n 1 ${XARGS_REPL_OPT} /bin/bash -c 'kill $(cat "'"${XARGS_REPL_STR}"'/tasks") 2> /dev/null' 196 197 sleep 2 198 199 # Really kill any leftover tasks 200 find $TMP/${cgroup_subsys}_test -mindepth 1 -depth -type d -print0 | \ 201 xargs -0r -n 1 ${XARGS_REPL_OPT} /bin/bash -c 'kill -s SIGKILL $(cat "'"${XARGS_REPL_STR}"'/tasks") 2> /dev/null' 202 203 # Don't need to run these xargs commands in bash since we want 204 # to see what's left on stdout 205 LINES=$(find $TMP/${cgroup_subsys}_test -mindepth 1 -depth -type d -print0 | \ 206 xargs -0r -n 1 ${XARGS_REPL_OPT} cat "${XARGS_REPL_STR}/tasks" | wc -l) 207 if (( LINES == 0 )); then 208 # Remove the empty groups 209 find $TMP/${cgroup_subsys}_test -mindepth 1 -depth -type d -print0 | xargs -r0 rmdir 210 else 211 tst_resm TWARN "Could not cleanup:" 212 find $TMP/${cgroup_subsys}_test -mindepth 1 -depth -type d -print0 | xargs -0r -n 1 ${XARGS_REPL_OPT} ls -ld "${XARGS_REPL_STR}/tasks" 213 fi 214 215 umount_freezer 216 } 217 218 if [ "$save_pwd" != `pwd` ]; then 219 tst_resm TWARN "libcgroup_subsys: cleanup_freezer() is broken" 220 cd "$save_pwd" 221 fi 222 223 result="${save_result}" 224} 225 226function umount_signal() 227{ 228 [ "${cgroup_subsys}" != "signal" ] && { 229 result=${result:-6} 230 exit -1 231 } 232 umount_cgroup_subsys 233 unset cgroup_subsys 234} 235 236function cleanup_signal() 237{ 238 local save_result="${result}" 239 local save_pwd="$(pwd)" 240 241 mount_signal && { 242 find $TMP/${cgroup_subsys}_test -mindepth 1 -depth -type d -print0 | xargs -r0 rmdir 243 umount_signal 244 } 245 246 if [ "$save_pwd" != `pwd` ]; then 247 tst_resm TWARN "libcgroup_subsys: cleanup_signal() is broken" 248 cd "$save_pwd" 249 fi 250 result="${save_result}" 251} 252 253function assert_cgroup_rwfile() 254{ 255 local file="$1" 256 local descr="$2" 257 local rc=0 258 259 if [ ! -e "${file}" ]; then 260 tst_resm ${LIB_TEST_STATE} "$descr missing" 261 rc=1 262 fi 263 264 if [ ! -f "${file}" ]; then 265 tst_resm ${LIB_TEST_STATE} "$descr is not a regular file" 266 rc=2 267 fi 268 269 if [ ! -r "${file}" ]; then 270 tst_resm ${LIB_TEST_STATE} "$descr is not readable" 271 rc=3 272 fi 273 274 if [ ! -w "${file}" ]; then 275 tst_resm ${LIB_TEST_STATE} "$descr is not writeable" 276 rc=4 277 fi 278 279 [ $rc -ne 0 ] && { 280 result=${result:-$rc} 281 local s="$(stat "${file}")" 282 tst_resm ${LIB_TEST_STATE} "${s}" 283 } 284 285 return $rc 286} 287 288function assert_cgroup_tasks_rwfile() 289{ 290 assert_cgroup_rwfile "tasks" "task list" 291 return $? 292} 293 294function dump_named_cgroup_tasks() 295{ 296 local cgroup_name="$1" 297 local tasks 298 299 tasks=( $(cat "${cgroup_name}/tasks") ) # don't assign directly (bash bug) 300 if [ -z "${tasks[*]}" ]; then 301 return 0 302 fi 303 ps -p "${tasks[*]}" -o 'pid,ppid,pgid,tid,tpgid,blocked,ignored,pending,stat,tty,args' 304} 305 306function dump_cgroup_tasks() 307{ 308 dump_named_cgroup_tasks "$(pwd)" 309} 310 311function assert_cgroup_tasks_empty() 312{ 313 local nlines=$(( `cat tasks | wc -l` + 0)) 314 local rc=$? 315 316 [ $rc -eq 0 -a $nlines -eq 0 ] && return 0 317 rc=$? 318 result=${result:-$rc} 319 tst_resm ${LIB_TEST_STATE} "cgroup task list is not empty: " 320 dump_cgroup_tasks 1>&2 321 return $rc 322} 323 324function assert_task_in_named_cgroup() 325{ 326 local task_pid=$1 327 local cgroup_name="$2" 328 329 cat "${cgroup_name}/tasks" | grep -E "^${task_pid}\$" > /dev/null 2>&1 && return 0 330 local rc=$? 331 result=${result:-$rc} 332 tst_resm ${LIB_TEST_STATE} "Expected pid ${task_pid} is not in \"${cgroup_name}\" task list" 333 dump_named_cgroup_tasks "${cgroup_name}" 1>&2 334 return $rc 335} 336 337function assert_task_not_in_named_cgroup() 338{ 339 local task_pid=$1 340 local cgroup_name="$2" 341 342 cat "${cgroup_name}/tasks" | grep -E "^${task_pid}\$" > /dev/null 2>&1 || return 0 343 local rc=1 # $? == 0 is an error in this case 344 result=${result:-$rc} 345 tst_resm ${LIB_TEST_STATE} "Expected pid ${task_pid} is in \"${cgroup_name}\" task list" 346 dump_named_cgroup_tasks "${cgroup_name}" 1>&2 347 return $rc 348} 349 350function assert_task_in_cgroup() 351{ 352 assert_task_in_named_cgroup $1 "$(pwd)" 353 return $? 354} 355 356function assert_task_not_in_cgroup() 357{ 358 assert_task_not_in_named_cgroup $1 "$(pwd)" 359 return $? 360} 361 362function assert_sample_proc_in_cgroup() 363{ 364 assert_task_in_cgroup $sample_proc 365 return $? 366} 367 368function assert_sample_proc_not_in_cgroup() 369{ 370 assert_task_not_in_cgroup $sample_proc 371 return $? 372} 373 374function assert_sample_proc_in_named_cgroup() 375{ 376 assert_task_in_named_cgroup $sample_proc "$1" 377 return $? 378} 379 380function assert_sample_proc_not_in_named_cgroup() 381{ 382 assert_task_not_in_named_cgroup $sample_proc "$1" 383 return $? 384} 385 386function get_task_state() 387{ 388 ps -p $1 -o 'state=' 2>/dev/null 389} 390 391# TODO Check: Do these need to ignore case differences? 392function assert_task_state() 393{ 394 local task_pid=$1 395 local expected_state="$2" 396 local ps_state="$(get_task_state ${task_pid})" 397 local rc=$? 398 399 [ $rc -eq 0 -a "$ps_state" == "${expected_state}" ] && return 0 400 rc=$? 401 result=${result:-$rc} 402 tst_resm ${LIB_TEST_STATE} "Expected task ${task_pid} to be in state \"${expected_state}\"" 403 return $rc 404} 405 406# 407# Check that the specified task is not in the specified state 408# 409function assert_task_not_in_state() 410{ 411 local task_pid=$1 412 local expected_state="$2" 413 local ps_state="$(get_task_state ${task_pid})" 414 local rc=$? 415 416 [ $rc -eq 0 -a "$ps_state" != "${expected_state}" ] && return 0 417 rc=$? 418 result=${result:-$rc} 419 tst_resm ${LIB_TEST_STATE} "Expected task ${task_pid} to not be in state \"${expected_state}\"" 420 return $rc 421} 422 423# 424# Frozen tasks are in the "D" state according to ps 425# tasks in "T" state may also be in a "frozen" state 426# 427function assert_task_not_frozen() 428{ 429 local task_pid=$1 430 local ps_state="$(ps -p $task_pid -o 'state=')" 431 local rc=$? 432 433 [ $rc -eq 0 -a "$ps_state" != "D" ] && return 0 434 rc=$? 435 result=${result:-$rc} 436 tst_resm ${LIB_TEST_STATE} "Expected task ${task_pid} is not frozen (unexpected task state: \"$ps_state\")" 437 return $rc 438} 439 440function assert_task_is_frozen() 441{ 442 local task_pid=$1 443 local ps_state="$(ps -p $task_pid -o 'state=')" 444 local rc=$? 445 446 [ $rc -eq 0 -a "$ps_state" == "D" -o "$ps_state" == "T" ] && return 0 447 rc=$? 448 result=${result:-$rc} 449 tst_resm ${LIB_TEST_STATE} "Expected task ${task_pid} to be frozen (unexpected task state: \"$ps_state\")" 450 return $rc 451} 452 453function assert_sample_proc_not_frozen() 454{ 455 assert_task_not_frozen $sample_proc 456 return $? 457} 458 459function assert_sample_proc_is_frozen() 460{ 461 assert_task_is_frozen $sample_proc 462 return $? 463} 464 465function assert_sample_proc_stopped() 466{ 467 assert_task_state $sample_proc 'T' 468 return $? 469} 470 471function assert_sample_proc_not_stopped() 472{ 473 assert_task_not_in_state $sample_proc 'T' 474 return $? 475} 476 477function assert_sample_proc_sleeping() 478{ 479 assert_task_state $sample_proc 'S' 480 return $? 481} 482 483function assert_sample_proc_not_sleeping() 484{ 485 assert_task_not_in_state $sample_proc 'S' 486 return $? 487} 488 489function assert_cgroup_subsys_state_rwfile() 490{ 491 if [ "${cgroup_subsys}" == "freezer" ]; then 492 assert_cgroup_rwfile "freezer.state" "freezer state" 493 return $? 494 elif [ "${cgroup_subsys}" == "freezer" ]; then 495 assert_cgroup_rwfile "signal.kill" "signal file" 496 return $? 497 else 498 return -1 499 fi 500} 501 502function get_freezer_state() 503{ 504 local state="$(cat freezer.state)" 505 local rc=$? 506 507 if [ $rc -ne 0 ]; then 508 result=${result:-$rc} 509 tst_resm ${LIB_TEST_STATE} "Failed to read freezer state." 510 return $rc 511 fi 512 echo "${state}" 513 return 0 514} 515 516function assert_cgroup_freezer_state() 517{ 518 local goal_state="$1" 519 local state="$(get_freezer_state)" 520 local rc=$? 521 522 [ $rc -eq 0 -a "${state}" == "${goal_state}" ] && return 0 523 rc=$? 524 result=${result:-$rc} 525 tst_resm ${LIB_TEST_STATE} "Expected freezer state \"$2\" but found freezer state: \"$state\"" 526 return $rc 527} 528 529function make_sample_cgroup_named() 530{ 531 local name="$1" 532 local saved_dir="$(pwd)" 533 mkdir "${name}" 534 local rc=$? 535 536 # So long as we made the directory we don't care 537 if [ ! -d "${name}" -a $rc -ne 0 ]; then 538 # But if it doesn't exist report the exit status of mkdir 539 result=${result:-$rc} 540 return $rc 541 fi 542 543 cd "${name}" > /dev/null 2>&1 544 545 rc=$? 546 if [ $rc -ne 0 ]; then 547 result=${result:-$rc} 548 return $rc 549 fi 550 551 assert_cgroup_tasks_rwfile || { 552 cd "${saved_dir}" 553 return $? 554 } 555 assert_cgroup_tasks_empty || { 556 cd "${saved_dir}" 557 return $? 558 } 559 assert_cgroup_subsys_state_rwfile || { 560 cd "${saved_dir}" 561 return $? 562 } 563 cd "${saved_dir}" 564 return 0 565} 566 567function make_sample_cgroup() 568{ 569 make_sample_cgroup_named "child" 570 local rc=$? 571 572 # So long as we made the directory we don't care 573 if [ $rc -ne 0 ]; then 574 return $rc 575 fi 576 577 cd "child" # we know this will succeed since make_sample_cgroup_named 578 # tested this 579 return 0 580} 581 582function rm_sample_cgroup_named() 583{ 584 local cgroup_name="$1" 585 local saved_dir="$(pwd)" 586 local rc=0 587 588 cd "${cgroup_name}" && { 589 assert_cgroup_tasks_rwfile || { 590 cd "${saved_dir}" 591 return $? 592 } 593 assert_cgroup_tasks_empty || { 594 cd "${saved_dir}" 595 return $? 596 } 597 assert_cgroup_subsys_state_rwfile || { 598 cd "${saved_dir}" 599 return $? 600 } 601 cd "${saved_dir}" 602 } || { 603 rc=$? 604 result=${result:-$rc} 605 return $rc 606 } 607 608 [ -d "${cgroup_name}" ] && rmdir "${cgroup_name}" && return 0 609 rc=$? 610 tst_resm TWARN "Failed to remove cgroup \"${cgroup_name}\"" 611 result=${result:-$rc} 612 return $rc 613} 614 615function rm_sample_cgroup() 616{ 617 local cgroup_name="$(basename $(pwd))" 618 local rc=0 619 620 cd .. || { 621 rc=$? 622 result=${result:-$rc} 623 return $rc 624 } 625 rm_sample_cgroup_named "${cgroup_name}" 626 return $? 627} 628 629function ls_pids() 630{ 631 ps -e -o 'pid=' | sed -e 's/[[:space:]]\+//g' 632} 633 634function assert_task_exists() 635{ 636 local task_pid=$1 637 638 ls_pids | grep -E "^${task_pid}\$" > /dev/null 2>&1 && return 0 639 local rc=$? 640 641 result=${result:-$rc} 642 tst_resm ${LIB_TEST_STATE} "Expected pid ${task_pid} does not exist" 643 return $rc 644} 645 646function assert_task_does_not_exist() 647{ 648 local task_pid=$1 649 650 ls_pids | grep -E "^${task_pid}\$" > /dev/null 2>&1 || return 0 651 local rc=1 # $? == 0 is an error in this case 652 653 result=${result:-$rc} 654 tst_resm ${LIB_TEST_STATE} "Did not expect pid ${task_pid} to exist" 655 return $rc 656} 657 658function assert_sample_proc_exists() 659{ 660 assert_task_exists $sample_proc 661 return $? 662} 663 664function assert_sample_proc_does_not_exist() 665{ 666 assert_task_does_not_exist $sample_proc 667 return $rc 668} 669 670function start_sample_proc() 671{ 672 local sample_cmd="/bin/sleep" 673 local args 674 675 args=( $sample_sleep ) # can't assign directly because of bash v2/v3 inconsistency 676 if [ $# -gt 0 ]; then 677 sample_cmd="$1" 678 shift 1 679 args=( "$@" ) 680 fi 681 682 [ -n "$sample_proc" ] && assert_sample_proc_does_not_exist 683 684 "$sample_cmd" "${args[@]}" & 685 local rc=$? 686 export sample_proc=$! 687 assert_sample_proc_exists 688 689 return $rc 690} 691 692function add_sample_proc_to_named_cgroup() 693{ 694 local cgroup_name="$1" 695 696 assert_sample_proc_exists 697 "${CG_FILE_WRITE}" $sample_proc > "${cgroup_name}/tasks" 698 local rc=$? 699 if [ $rc -ne 0 ]; then 700 result=${result:-$rc} 701 tst_resm ${LIB_TEST_STATE} "Failed to add sample process $sample_proc to cgroup \"${cgroup_name}\"" 702 return $rc 703 fi 704 assert_task_in_named_cgroup $sample_proc "${cgroup_name}" 705 return $? 706} 707 708function add_sample_proc_to_cgroup() 709{ 710 add_sample_proc_to_named_cgroup "$(pwd)" 711 return $? 712} 713 714function kill_sample_proc() 715{ 716 if [ -z "$sample_proc" ]; then 717 # It's no longer running or never started. 718 # If it was supposed to have started but did not then that 719 # should be determined by checking start_sample_proc results. 720 return 0 721 fi 722 723 # Hey, bash, don't print out any of your messy job status notices 724 disown -a 725 726 if [ "$(get_task_state $sample_proc)" == "D" ]; then 727 tst_resm TWARN "sample process is frozen stiff" 728 kill $sample_proc 729 local rc=$? 730 result=${result:-$rc} 731 return $rc 732 fi 733 734 # kill child processes of the sample process 735 while pgrep -P $sample_proc ; do 736 pkill -SIGTERM -P $sample_proc 737 sleep 1 738 pkill -SIGKILL -P $sample_proc 739 740 ps -p $(pgrep -P $sample_proc) -o 'state=' | grep -v D && continue 741 # Give up if all the child processes are frozen in D state or 742 # if there aren't any more child processes 743 break 744 done 745 # DEBUG dump pstree under $sample_proc: 746 # pstree -A -p $sample_proc 747 kill $sample_proc > /dev/null 2>&1 || kill -s SIGKILL $sample_proc > /dev/null 2>&1 || { 748 local rc=$? 749 750 ps -p $sample_proc -o 'state=' > /dev/null 2>&1 751 if [ $? -eq 1 ]; then 752 # It's dead. We're OK. 753 return 0 754 fi 755 # It's still alive somehow! Give up. 756 result=${result:-$rc} 757 tst_resm TWARN "Failed to kill sample process $sample_proc (kill exit status: $rc)" 758 } 759 assert_sample_proc_not_in_cgroup 760 assert_sample_proc_does_not_exist 761 return $? 762} 763 764function issue_freeze_cmd() 765{ 766 local goal_state="FROZEN" 767 local sample_state_count=1 768 local state="$(get_freezer_state)" 769 local rc=$? 770 771 if [ $rc -ne 0 ]; then 772 return $rc 773 fi 774 775 while [ "${state}" != "${goal_state}" ]; do 776 "${CG_FILE_WRITE}" "${FREEZE}" > freezer.state 777 sleep $sample_state_period 778 state="$(get_freezer_state)" 779 rc=$? 780 if [ $rc -ne 0 ]; then 781 break 782 fi 783 784 ((sample_state_count++)) 785 if [ "$sample_state_count" -ge "$max_state_samples" ]; then 786 break 787 fi 788 done 789 790 if [ "${state}" == "${goal_state}" ]; then 791 return 0 792 fi 793 794 result=${result:-$rc} 795 tst_resm ${LIB_TEST_STATE} "Failed to issue freeze command (freezer state: \"`get_freezer_state`\")." 796 return $rc 797} 798 799# If we're trying to "freeze" tasks with SIGTOP 800function issue_stop_as_freeze_cmd() 801{ 802 local goal_state="T" 803 local sample_state_count=1 804 local ps_state="$(get_task_state ${task_pid})" 805 local rc=$? 806 807 if [ $rc -ne 0 ]; then 808 return $rc 809 fi 810 811 while [ "${ps_state}" != "${goal_state}" ]; do 812 kill -s SIGSTOP $sample_proc 813 sleep $sample_state_period 814 ps_state="$(get_task_state ${task_pid})" 815 rc=$? 816 if [ $rc -ne 0 ]; then 817 break 818 fi 819 820 ((sample_state_count++)) 821 if [ "$sample_state_count" -ge "$max_state_samples" ]; then 822 break 823 fi 824 done 825 826 if [ "${ps_state}" == "${goal_state}" ]; then 827 return 0 828 fi 829 830 result=${result:-$rc} 831 tst_resm ${LIB_TEST_STATE} "Failed to issue stop (freeze) command (task state: \"${ps_state}\")." 832 return $rc 833} 834 835function send_signal() 836{ 837 "${CG_FILE_WRITE}" $1 > 'signal.kill' && return 0 838 local rc=$? 839 result=${result:-$rc} 840 tst_resm ${LIB_TEST_STATE} "Failed to send signal: $1 to tasks in cgroup (rc: $rc)" 841 return $rc 842} 843 844function wait_until_goal_state_or_timeout() 845{ 846 local goal_state="$1" 847 local sample_state_count=1 848 local state="$(get_freezer_state)" 849 local rc=$? 850 851 if [ $rc -ne 0 ]; then 852 return $rc 853 fi 854 855 while [ "${state}" != "${goal_state}" ]; do 856 sleep $sample_state_period 857 state="$(get_freezer_state)" 858 rc=$? 859 if [ $rc -ne 0 ]; then 860 break 861 fi 862 863 ((sample_state_count++)) 864 if [ "$sample_state_count" -ge "$max_state_samples" ]; then 865 break 866 fi 867 done 868 return $rc 869} 870 871# TODO convert signal scripts -- insert task between until and goal 872function wait_until_sample_proc_goal_state_or_timeout() 873{ 874 local goal_state="$1" 875 local sample_state_count=1 876 local ps_state="$(get_task_state ${sample_proc})" 877 local rc=$? 878 879 while [ $rc -eq 0 -a "${ps_state}" != "${goal_state}" -a \ 880 "$sample_state_count" -lt "$max_state_samples" ]; do 881 sleep $sample_state_period 882 ps_state="$(get_task_state ${sample_proc})" 883 rc=$? 884 if [ $rc -ne 0 ]; then 885 result=${result:-$rc} 886 tst_resm ${LIB_TEST_STATE} "Failed to read process state." 887 break 888 fi 889 890 ((sample_state_count++)) 891 done 892 return $rc 893} 894 895# TODO convert signal scripts -- insert task between until and not 896function wait_until_sample_proc_not_goal_state_or_timeout() 897{ 898 local goal_state="$1" 899 local sample_state_count=1 900 local ps_state="$(get_task_state ${sample_proc})" 901 local rc=$? 902 903 while [ $rc -eq 0 -a "${ps_state}" == "${goal_state}" -a \ 904 "$sample_state_count" -lt "$max_state_samples" ]; do 905 sleep $sample_state_period 906 ps_state="$(get_task_state ${sample_proc})" 907 rc=$? 908 if [ $rc -ne 0 ]; then 909 result=${result:-$rc} 910 tst_resm ${LIB_TEST_STATE} "Failed to read process state." 911 break 912 fi 913 914 ((sample_state_count++)) 915 done 916 return $rc 917} 918 919function wait_until_frozen() 920{ 921 wait_until_goal_state_or_timeout "FROZEN" || return $? 922 assert_cgroup_freezer_state "FROZEN" "ERROR: failed to freeze cgroup" 923 # TODO assert all tasks in cgroup are in 'D' or 'T' state 924 # TODO assert that trying to add a task to cgroup results in EBUSY 925 return $? 926} 927 928function issue_thaw_cmd() 929{ 930 "${CG_FILE_WRITE}" "${THAW}" > freezer.state && return 0 931 local rc=$? 932 result=${result:-$rc} 933 tst_resm ${LIB_TEST_STATE} "Failed to issue thaw command." 934 return $rc 935} 936 937function issue_cont_as_thaw_cmd() 938{ 939 local goal_state="T" 940 local sample_state_count=1 941 local ps_state="$(get_task_state ${task_pid})" 942 local rc=$? 943 944 if [ $rc -ne 0 ]; then 945 return $rc 946 fi 947 948 while [ "${ps_state}" == "${goal_state}" ]; do 949 kill -s SIGCONT $sample_proc 950 sleep $sample_state_period 951 ps_state="$(get_task_state ${task_pid})" 952 rc=$? 953 if [ $rc -ne 0 ]; then 954 break 955 fi 956 957 ((sample_state_count++)) 958 if [ "$sample_state_count" -ge "$max_state_samples" ]; then 959 break 960 fi 961 done 962 963 if [ "${ps_state}" != "${goal_state}" ]; then 964 return 0 965 fi 966 967 result=${result:-$rc} 968 tst_resm ${LIB_TEST_STATE} "Failed to issue continue (thaw) command (task state: \"${ps_state}\")." 969 return $rc 970} 971 972function wait_until_thawed() 973{ 974 wait_until_goal_state_or_timeout "THAWED" || return $? 975 assert_cgroup_freezer_state "THAWED" "ERROR: Failed to thaw cgroup." 976 return $? 977} 978 979function wait_until_freezing() 980{ 981 wait_until_goal_state_or_timeout "FREEZING" 982 # Time critical -- we race with the kernel as it freezes tasks in the 983 # cgroup. So rather than assert "FREEZING" we just return 984 return $? 985} 986 987function wait_until_sample_proc_stopped() 988{ 989 wait_until_sample_proc_state_or_timeout 'T' || return $? 990 assert_sample_proc_stopped 991 return $? 992} 993 994function wait_until_sample_proc_not_stopped() 995{ 996 wait_until_sample_proc_not_goal_state_or_timeout 'T' || return $? 997 assert_sample_proc_not_stopped 998 return $? 999} 1000