Use GDB to dump threads in test timeouts, if available.
GDB is able to dump threads which may not be responding to the SIGQUIT
thread dump.
Bug: 23485091
Change-Id: Ib80db4e63258887f3b7c313ed5e6eb9e6300ac4c
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 39dc030..f45e6f5 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -37,9 +37,9 @@
QUIET="n"
RELOCATE="y"
SECONDARY_DEX=""
-TIME_OUT="y"
-# Value in minutes.
-TIME_OUT_VALUE=10
+TIME_OUT="gdb" # "n" (disabled), "timeout" (use timeout), "gdb" (use gdb)
+# Value in seconds
+TIME_OUT_VALUE=600 # 10 minutes.
USE_GDB="n"
USE_JVM="n"
VERIFY="y" # y=yes,n=no,s=softfail
@@ -459,15 +459,29 @@
cmdline="$dalvikvm_cmdline"
- if [ "$TIME_OUT" = "y" ]; then
+ if [ "$TIME_OUT" = "gdb" ]; then
+ if [ `uname` = "Darwin" ]; then
+ # Fall back to timeout on Mac.
+ TIME_OUT="timeout"
+ else
+ # Check if gdb is available.
+ gdb --eval-command="quit" > /dev/null 2>&1
+ if [ $? != 0 ]; then
+ # gdb isn't available. Fall back to timeout.
+ TIME_OUT="timeout"
+ fi
+ fi
+ fi
+
+ if [ "$TIME_OUT" = "timeout" ]; then
# Add timeout command if time out is desired.
#
# Note: We use nested timeouts. The inner timeout sends SIGRTMIN+2 (usually 36) to ART, which
# will induce a full thread dump before abort. However, dumping threads might deadlock,
# so the outer timeout sends the regular SIGTERM after an additional minute to ensure
# termination (without dumping all threads).
- TIME_PLUS_ONE=$(($TIME_OUT_VALUE + 1))
- cmdline="timeout ${TIME_PLUS_ONE}m timeout -s SIGRTMIN+2 ${TIME_OUT_VALUE}m $cmdline"
+ TIME_PLUS_ONE=$(($TIME_OUT_VALUE + 60))
+ cmdline="timeout ${TIME_PLUS_ONE}s timeout -s SIGRTMIN+2 ${TIME_OUT_VALUE}s $cmdline"
fi
if [ "$DEV_MODE" = "y" ]; then
@@ -502,12 +516,37 @@
# When running under gdb, we cannot do piping and grepping...
$cmdline "$@"
else
- trap 'kill -INT -$pid' INT
- $cmdline "$@" 2>&1 & pid=$!
- wait $pid
- # Add extra detail if time out is enabled.
- if [ ${PIPESTATUS[0]} = 124 ] && [ "$TIME_OUT" = "y" ]; then
- echo -e "\e[91mTEST TIMED OUT!\e[0m" >&2
+ if [ "$TIME_OUT" != "gdb" ]; then
+ trap 'kill -INT -$pid' INT
+ $cmdline "$@" 2>&1 & pid=$!
+ wait $pid
+ # Add extra detail if time out is enabled.
+ if [ ${PIPESTATUS[0]} = 124 ] && [ "$TIME_OUT" = "timeout" ]; then
+ echo -e "\e[91mTEST TIMED OUT!\e[0m" >&2
+ fi
+ else
+ # With a thread dump that uses gdb if a timeout.
+ trap 'kill -INT -$pid' INT
+ $cmdline "$@" 2>&1 & pid=$!
+ # Spawn a watcher process.
+ ( sleep $TIME_OUT_VALUE && \
+ echo "##### Thread dump using gdb on test timeout" && \
+ ( gdb -q -p $pid --eval-command="info thread" --eval-command="thread apply all bt" \
+ --eval-command="call exit(124)" --eval-command=quit || \
+ kill $pid )) 2> /dev/null & watcher=$!
+ wait $pid
+ test_exit_status=$?
+ pkill -P $watcher 2> /dev/null # kill the sleep which will in turn end the watcher as well
+ if [ $test_exit_status = 0 ]; then
+ # The test finished normally.
+ exit 0
+ else
+ # The test failed or timed out.
+ if [ $test_exit_status = 124 ]; then
+ # The test timed out.
+ echo -e "\e[91mTEST TIMED OUT!\e[0m" >&2
+ fi
+ fi
fi
fi
fi