libcgroup_freezer 23 KB

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