6964018: 3/4 AnonLoggerWeakRefLeak and LoggerWeakRefLeak can fail in JPRT
Summary: Refactor test/sun/tools/common/* code and refactor AnonLoggerWeakRefLeak and LoggerWeakRefLeak to use it.
Reviewed-by: ohair, alanb
--- a/jdk/test/java/util/logging/AnonLoggerWeakRefLeak.java Wed Jul 21 16:59:40 2010 -0700
+++ b/jdk/test/java/util/logging/AnonLoggerWeakRefLeak.java Wed Jul 21 17:01:31 2010 -0700
@@ -23,24 +23,32 @@
import java.util.logging.*;
-public class AnonLoggerWeakRefLeak {
- public static int DEFAULT_LOOP_TIME = 60; // time is in seconds
+public class AnonLoggerWeakRefLeak extends SimpleApplication {
+ // The test driver script will allow this program to run until we
+ // reach DEFAULT_LOOP_TIME or a decrease in instance counts is
+ // observed. For this particular WeakReference leak, the count
+ // was always observed to be increasing so if we get a decreasing
+ // count, then the leak is fixed in the bits being tested.
+ // Two minutes has been enough time to observe a decrease in
+ // fixed bits on overloaded systems, but the test will likely
+ // finish more quickly.
+ public static int DEFAULT_LOOP_TIME = 120; // time is in seconds
- public static void main(String[] args) {
+ // execute the AnonLoggerWeakRefLeak app work
+ public void doMyAppWork(String[] args) throws Exception {
int loop_time = 0;
int max_loop_time = DEFAULT_LOOP_TIME;
- if (args.length == 0) {
+ // args[0] is the port-file
+ if (args.length < 2) {
System.out.println("INFO: using default time of "
+ max_loop_time + " seconds.");
} else {
try {
- max_loop_time = Integer.parseInt(args[0]);
+ max_loop_time = Integer.parseInt(args[1]);
} catch (NumberFormatException nfe) {
- System.err.println("Error: '" + args[0]
+ throw new RuntimeException("Error: '" + args[1]
+ "': is not a valid seconds value.");
- System.err.println("Usage: AnonLoggerWeakRefLeak [seconds]");
- System.exit(1);
}
}
@@ -73,4 +81,12 @@
System.out.println("INFO: final loop count = " + count);
}
+
+ public static void main(String[] args) throws Exception {
+ AnonLoggerWeakRefLeak myApp = new AnonLoggerWeakRefLeak();
+
+ SimpleApplication.setMyApp(myApp);
+
+ SimpleApplication.main(args);
+ }
}
--- a/jdk/test/java/util/logging/AnonLoggerWeakRefLeak.sh Wed Jul 21 16:59:40 2010 -0700
+++ b/jdk/test/java/util/logging/AnonLoggerWeakRefLeak.sh Wed Jul 21 17:01:31 2010 -0700
@@ -1,3 +1,5 @@
+#!/bin/sh
+
#
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -23,76 +25,24 @@
# @test
# @bug 6942989
-# @ignore until 6964018 is fixed
# @summary Check for WeakReference leak in anonymous Logger objects
# @author Daniel D. Daugherty
#
-# @run build AnonLoggerWeakRefLeak
-# @run shell/timeout=180 AnonLoggerWeakRefLeak.sh
+# @library ../../../sun/tools/common
+# @build SimpleApplication ShutdownSimpleApplication
+# @build AnonLoggerWeakRefLeak
+# @run shell/timeout=240 AnonLoggerWeakRefLeak.sh
-# The timeout is: 2 minutes for infrastructure and 1 minute for the test
+# The timeout is: 2 minutes for infrastructure and 2 minutes for the test
#
-if [ "${TESTJAVA}" = "" ]
-then
- echo "TESTJAVA not set. Test cannot execute. Failed."
- exit 1
-fi
-
-if [ "${TESTSRC}" = "" ]
-then
- echo "TESTSRC not set. Test cannot execute. Failed."
- exit 1
-fi
+. ${TESTSRC}/../../../sun/tools/common/CommonSetup.sh
+. ${TESTSRC}/../../../sun/tools/common/ApplicationSetup.sh
-if [ "${TESTCLASSES}" = "" ]
-then
- echo "TESTCLASSES not set. Test cannot execute. Failed."
- exit 1
-fi
-
-JAVA="${TESTJAVA}"/bin/java
-JMAP="${TESTJAVA}"/bin/jmap
-JPS="${TESTJAVA}"/bin/jps
-
-set -eu
TEST_NAME="AnonLoggerWeakRefLeak"
TARGET_CLASS="java\.lang\.ref\.WeakReference"
-is_cygwin=false
-is_mks=false
-is_windows=false
-
-case `uname -s` in
-CYGWIN*)
- is_cygwin=true
- is_windows=true
- ;;
-Windows_*)
- is_mks=true
- is_windows=true
- ;;
-*)
- ;;
-esac
-
-
-# wrapper for grep
-#
-grep_cmd() {
- set +e
- if $is_windows; then
- # need dos2unix to get rid of CTRL-M chars from java output
- dos2unix | grep "$@"
- status="$?"
- else
- grep "$@"
- status="$?"
- fi
- set -e
-}
-
# MAIN begins here
#
@@ -105,62 +55,39 @@
# see if this version of jmap supports the '-histo:live' option
jmap_option="-histo:live"
set +e
-"${JMAP}" "$jmap_option" 0 > "$TEST_NAME.jmap" 2>&1
-grep '^Usage: ' "$TEST_NAME.jmap" > /dev/null 2>&1
+"${JMAP}" 2>&1 | grep ':live' > /dev/null 2>&1
status="$?"
set -e
-if [ "$status" = 0 ]; then
+if [ "$status" != 0 ]; then
echo "INFO: switching jmap option from '$jmap_option'\c"
jmap_option="-histo"
echo " to '$jmap_option'."
fi
-"${JAVA}" ${TESTVMOPTS} -classpath "${TESTCLASSES}" \
- "$TEST_NAME" $seconds > "$TEST_NAME.log" 2>&1 &
-test_pid="$!"
-echo "INFO: starting $TEST_NAME as pid = $test_pid"
-
-# wait for test program to get going
-count=0
-while [ "$count" -lt 30 ]; do
- sleep 2
- grep_cmd '^INFO: call count = 0$' < "$TEST_NAME.log" > /dev/null 2>&1
- if [ "$status" = 0 ]; then
- break
- fi
- count=`expr $count + 1`
-done
+# Start application and use TEST_NAME.port for coordination
+startApplication "$TEST_NAME" "$TEST_NAME.port" $seconds
-if [ "$count" -ge 30 ]; then
- echo "ERROR: $TEST_NAME failed to get going." >&2
- echo "INFO: killing $test_pid"
- kill "$test_pid"
- exit 1
-elif [ "$count" -gt 1 ]; then
- echo "INFO: $TEST_NAME took $count loops to start."
-fi
-
-if $is_cygwin; then
- # We need the Windows pid for jmap and not the Cygwin pid.
- # Note: '\t' works on Cygwin, but doesn't seem to work on Solaris.
- jmap_pid=`"${JPS}"| grep_cmd "[ \t]$TEST_NAME$" | sed 's/[ \t].*//'`
- if [ -z "$jmap_pid" ]; then
- echo "FAIL: jps could not map Cygwin pid to Windows pid." >&2
- echo "INFO: killing $test_pid"
- kill "$test_pid"
- exit 2
- fi
- echo "INFO: pid = $test_pid maps to Windows pid = $jmap_pid"
-else
- jmap_pid="$test_pid"
-fi
+finished_early=false
decreasing_cnt=0
increasing_cnt=0
loop_cnt=0
prev_instance_cnt=0
+MAX_JMAP_TRY_CNT=10
+jmap_retry_cnt=0
+loop_cnt_on_retry=0
+
while true; do
+ # see if the target process has finished its run and bail if it has
+ set +e
+ grep "^INFO: final loop count = " "$appOutput" > /dev/null 2>&1
+ status="$?"
+ set -e
+ if [ "$status" = 0 ]; then
+ break
+ fi
+
# Output format for 'jmap -histo' in JDK1.5.0:
#
# <#bytes> <#instances> <class_name>
@@ -170,38 +97,70 @@
# <num>: <#instances> <#bytes> <class_name>
#
set +e
- "${JMAP}" "$jmap_option" "$jmap_pid" > "$TEST_NAME.jmap" 2>&1
+ "${JMAP}" "$jmap_option" "$appJavaPid" > "$TEST_NAME.jmap" 2>&1
status="$?"
set -e
if [ "$status" != 0 ]; then
echo "INFO: jmap exited with exit code = $status"
- if [ "$loop_cnt" = 0 ]; then
- echo "INFO: on the first iteration so no samples were taken."
- echo "INFO: start of jmap output:"
- cat "$TEST_NAME.jmap"
- echo "INFO: end of jmap output."
+
+ # There are intermittent jmap failures; see 6498448.
+ #
+ # So far the following have been observed in a jmap call
+ # that was not in a race with target process termination:
+ #
+ # (Solaris specific, 2nd sample)
+ # <pid>: Unable to open door: target process not responding or HotSpot VM not loaded
+ # The -F option can be used when the target process is not responding
+ #
+ # (on Solaris so far)
+ # java.io.IOException
+ #
+ # (on Solaris so far, 1st sample)
+ # <pid>: Permission denied
+ #
+ sed 's/^/INFO: /' "$TEST_NAME.jmap"
+
+ if [ "$loop_cnt" = "$loop_cnt_on_retry" ]; then
+ # loop count hasn't changed
+ jmap_retry_cnt=`expr $jmap_retry_cnt + 1`
+ else
+ # loop count has changed so remember it
+ jmap_retry_cnt=1
+ loop_cnt_on_retry="$loop_cnt"
+ fi
+
+ # This is '-ge' because we have the original attempt plus
+ # MAX_JMAP_TRY_CNT - 1 retries.
+ if [ "$jmap_retry_cnt" -ge "$MAX_JMAP_TRY_CNT" ]; then
+ echo "INFO: jmap failed $MAX_JMAP_TRY_CNT times in a row" \
+ "without making any progress."
echo "FAIL: jmap is unable to take any samples." >&2
- echo "INFO: killing $test_pid"
- kill "$test_pid"
+ killApplication
exit 2
fi
- echo "INFO: The likely reason is that $TEST_NAME has finished running."
- break
+
+ # short delay and try again
+ # Note: sleep 1 didn't help with "<pid>: Permission denied"
+ sleep 2
+ echo "INFO: retrying jmap (retry=$jmap_retry_cnt, loop=$loop_cnt)."
+ continue
fi
- instance_cnt=`grep_cmd "[ ]$TARGET_CLASS$" \
- < "$TEST_NAME.jmap" \
+ set +e
+ instance_cnt=`grep "${PATTERN_WS}${TARGET_CLASS}${PATTERN_EOL}" \
+ "$TEST_NAME.jmap" \
| sed '
# strip leading whitespace; does nothing in JDK1.5.0
- s/^[ ][ ]*//
+ s/^'"${PATTERN_WS}${PATTERN_WS}"'*//
# strip <#bytes> in JDK1.5.0; does nothing otherwise
- s/^[1-9][0-9]*[ ][ ]*//
+ s/^[1-9][0-9]*'"${PATTERN_WS}${PATTERN_WS}"'*//
# strip <num>: field; does nothing in JDK1.5.0
- s/^[1-9][0-9]*:[ ][ ]*//
+ s/^[1-9][0-9]*:'"${PATTERN_WS}${PATTERN_WS}"'*//
# strip <class_name> field
- s/[ ].*//
+ s/'"${PATTERN_WS}"'.*//
'`
+ set -e
if [ -z "$instance_cnt" ]; then
echo "INFO: instance count is unexpectedly empty"
if [ "$loop_cnt" = 0 ]; then
@@ -211,8 +170,7 @@
cat "$TEST_NAME.jmap"
echo "INFO: end of jmap output."
echo "FAIL: cannot find the instance count value." >&2
- echo "INFO: killing $test_pid"
- kill "$test_pid"
+ killApplication
exit 2
fi
else
@@ -221,7 +179,17 @@
if [ "$instance_cnt" -gt "$prev_instance_cnt" ]; then
increasing_cnt=`expr $increasing_cnt + 1`
else
+ # actually decreasing or the same
decreasing_cnt=`expr $decreasing_cnt + 1`
+
+ # For this particular WeakReference leak, the count was
+ # always observed to be increasing so if we get a decreasing
+ # or the same count, then the leak is fixed in the bits
+ # being tested.
+ echo "INFO: finishing early due to non-increasing instance count."
+ finished_early=true
+ killApplication
+ break
fi
prev_instance_cnt="$instance_cnt"
fi
@@ -232,8 +200,22 @@
loop_cnt=`expr $loop_cnt + 1`
done
+if [ $finished_early = false ]; then
+ stopApplication "$TEST_NAME.port"
+ waitForApplication
+fi
+
+echo "INFO: $TEST_NAME has finished running."
echo "INFO: increasing_cnt = $increasing_cnt"
echo "INFO: decreasing_cnt = $decreasing_cnt"
+if [ "$jmap_retry_cnt" -gt 0 ]; then
+ echo "INFO: jmap_retry_cnt = $jmap_retry_cnt (in $loop_cnt iterations)"
+fi
+
+if [ "$loop_cnt" = 0 ]; then
+ echo "FAIL: jmap is unable to take any samples." >&2
+ exit 2
+fi
echo "INFO: The instance count of" `eval echo $TARGET_CLASS` "objects"
if [ "$decreasing_cnt" = 0 ]; then
@@ -242,6 +224,6 @@
exit 2
fi
-echo "INFO: is both increasing and decreasing."
+echo "INFO: is not always increasing."
echo "PASS: This indicates that there is not a memory leak."
exit 0
--- a/jdk/test/java/util/logging/LoggerWeakRefLeak.java Wed Jul 21 16:59:40 2010 -0700
+++ b/jdk/test/java/util/logging/LoggerWeakRefLeak.java Wed Jul 21 17:01:31 2010 -0700
@@ -23,27 +23,32 @@
import java.util.logging.*;
-public class LoggerWeakRefLeak {
- // AnonLoggerWeakRefLeak checks for one weak reference leak.
- // LoggerWeakRefLeak checks for two weak reference leaks so
- // this test runs twice as long, by default.
+public class LoggerWeakRefLeak extends SimpleApplication {
+ // The test driver script will allow this program to run until we
+ // reach DEFAULT_LOOP_TIME or a decrease in instance counts is
+ // observed. For these particular WeakReference leaks, the count
+ // was always observed to be increasing so if we get a decreasing
+ // count, then the leaks are fixed in the bits being tested.
+ // Two minutes has been enough time to observe a decrease in
+ // fixed bits on overloaded systems, but the test will likely
+ // finish more quickly.
public static int DEFAULT_LOOP_TIME = 120; // time is in seconds
- public static void main(String[] args) {
+ // execute the LoggerWeakRefLeak app work
+ public void doMyAppWork(String[] args) throws Exception {
int loop_time = 0;
int max_loop_time = DEFAULT_LOOP_TIME;
- if (args.length == 0) {
+ // args[0] is the port-file
+ if (args.length < 2) {
System.out.println("INFO: using default time of "
+ max_loop_time + " seconds.");
} else {
try {
- max_loop_time = Integer.parseInt(args[0]);
+ max_loop_time = Integer.parseInt(args[1]);
} catch (NumberFormatException nfe) {
- System.err.println("Error: '" + args[0]
+ throw new RuntimeException("Error: '" + args[1]
+ "': is not a valid seconds value.");
- System.err.println("Usage: LoggerWeakRefLeak [seconds]");
- System.exit(1);
}
}
@@ -86,4 +91,12 @@
System.out.println("INFO: final loop count = " + count);
}
+
+ public static void main(String[] args) throws Exception {
+ AnonLoggerWeakRefLeak myApp = new AnonLoggerWeakRefLeak();
+
+ SimpleApplication.setMyApp(myApp);
+
+ SimpleApplication.main(args);
+ }
}
--- a/jdk/test/java/util/logging/LoggerWeakRefLeak.sh Wed Jul 21 16:59:40 2010 -0700
+++ b/jdk/test/java/util/logging/LoggerWeakRefLeak.sh Wed Jul 21 17:01:31 2010 -0700
@@ -1,3 +1,5 @@
+#!/bin/sh
+
#
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -23,76 +25,24 @@
# @test
# @bug 6942989
-# @ignore until 6964018 is fixed
# @summary Check for WeakReference leak in Logger objects
# @author Daniel D. Daugherty
#
-# @run build LoggerWeakRefLeak
+# @library ../../../sun/tools/common
+# @build SimpleApplication ShutdownSimpleApplication
+# @build LoggerWeakRefLeak
# @run shell/timeout=240 LoggerWeakRefLeak.sh
-# The timeout is: 2 minutes for infrastructure and 1 minute for the test
+# The timeout is: 2 minutes for infrastructure and 2 minutes for the test
#
-if [ "${TESTJAVA}" = "" ]
-then
- echo "TESTJAVA not set. Test cannot execute. Failed."
- exit 1
-fi
-
-if [ "${TESTSRC}" = "" ]
-then
- echo "TESTSRC not set. Test cannot execute. Failed."
- exit 1
-fi
+. ${TESTSRC}/../../../sun/tools/common/CommonSetup.sh
+. ${TESTSRC}/../../../sun/tools/common/ApplicationSetup.sh
-if [ "${TESTCLASSES}" = "" ]
-then
- echo "TESTCLASSES not set. Test cannot execute. Failed."
- exit 1
-fi
-
-JAVA="${TESTJAVA}"/bin/java
-JMAP="${TESTJAVA}"/bin/jmap
-JPS="${TESTJAVA}"/bin/jps
-
-set -eu
TEST_NAME="LoggerWeakRefLeak"
TARGET_CLASS="java\.lang\.ref\.WeakReference"
-is_cygwin=false
-is_mks=false
-is_windows=false
-
-case `uname -s` in
-CYGWIN*)
- is_cygwin=true
- is_windows=true
- ;;
-Windows_*)
- is_mks=true
- is_windows=true
- ;;
-*)
- ;;
-esac
-
-
-# wrapper for grep
-#
-grep_cmd() {
- set +e
- if $is_windows; then
- # need dos2unix to get rid of CTRL-M chars from java output
- dos2unix | grep "$@"
- status="$?"
- else
- grep "$@"
- status="$?"
- fi
- set -e
-}
-
# MAIN begins here
#
@@ -105,62 +55,39 @@
# see if this version of jmap supports the '-histo:live' option
jmap_option="-histo:live"
set +e
-"${JMAP}" "$jmap_option" 0 > "$TEST_NAME.jmap" 2>&1
-grep '^Usage: ' "$TEST_NAME.jmap" > /dev/null 2>&1
+"${JMAP}" 2>&1 | grep ':live' > /dev/null 2>&1
status="$?"
set -e
-if [ "$status" = 0 ]; then
+if [ "$status" != 0 ]; then
echo "INFO: switching jmap option from '$jmap_option'\c"
jmap_option="-histo"
echo " to '$jmap_option'."
fi
-"${JAVA}" ${TESTVMOPTS} -classpath "${TESTCLASSES}" \
- "$TEST_NAME" $seconds > "$TEST_NAME.log" 2>&1 &
-test_pid="$!"
-echo "INFO: starting $TEST_NAME as pid = $test_pid"
-
-# wait for test program to get going
-count=0
-while [ "$count" -lt 30 ]; do
- sleep 2
- grep_cmd '^INFO: call count = 0$' < "$TEST_NAME.log" > /dev/null 2>&1
- if [ "$status" = 0 ]; then
- break
- fi
- count=`expr $count + 1`
-done
+# Start application and use TEST_NAME.port for coordination
+startApplication "$TEST_NAME" "$TEST_NAME.port" $seconds
-if [ "$count" -ge 30 ]; then
- echo "ERROR: $TEST_NAME failed to get going." >&2
- echo "INFO: killing $test_pid"
- kill "$test_pid"
- exit 1
-elif [ "$count" -gt 1 ]; then
- echo "INFO: $TEST_NAME took $count loops to start."
-fi
-
-if $is_cygwin; then
- # We need the Windows pid for jmap and not the Cygwin pid.
- # Note: '\t' works on Cygwin, but doesn't seem to work on Solaris.
- jmap_pid=`"${JPS}"| grep_cmd "[ \t]$TEST_NAME$" | sed 's/[ \t].*//'`
- if [ -z "$jmap_pid" ]; then
- echo "FAIL: jps could not map Cygwin pid to Windows pid." >&2
- echo "INFO: killing $test_pid"
- kill "$test_pid"
- exit 2
- fi
- echo "INFO: pid = $test_pid maps to Windows pid = $jmap_pid"
-else
- jmap_pid="$test_pid"
-fi
+finished_early=false
decreasing_cnt=0
increasing_cnt=0
loop_cnt=0
prev_instance_cnt=0
+MAX_JMAP_TRY_CNT=10
+jmap_retry_cnt=0
+loop_cnt_on_retry=0
+
while true; do
+ # see if the target process has finished its run and bail if it has
+ set +e
+ grep "^INFO: final loop count = " "$appOutput" > /dev/null 2>&1
+ status="$?"
+ set -e
+ if [ "$status" = 0 ]; then
+ break
+ fi
+
# Output format for 'jmap -histo' in JDK1.5.0:
#
# <#bytes> <#instances> <class_name>
@@ -170,38 +97,70 @@
# <num>: <#instances> <#bytes> <class_name>
#
set +e
- "${JMAP}" "$jmap_option" "$jmap_pid" > "$TEST_NAME.jmap" 2>&1
+ "${JMAP}" "$jmap_option" "$appJavaPid" > "$TEST_NAME.jmap" 2>&1
status="$?"
set -e
if [ "$status" != 0 ]; then
echo "INFO: jmap exited with exit code = $status"
- if [ "$loop_cnt" = 0 ]; then
- echo "INFO: on the first iteration so no samples were taken."
- echo "INFO: start of jmap output:"
- cat "$TEST_NAME.jmap"
- echo "INFO: end of jmap output."
+
+ # There are intermittent jmap failures; see 6498448.
+ #
+ # So far the following have been observed in a jmap call
+ # that was not in a race with target process termination:
+ #
+ # (Solaris specific, 2nd sample)
+ # <pid>: Unable to open door: target process not responding or HotSpot VM not loaded
+ # The -F option can be used when the target process is not responding
+ #
+ # (on Solaris so far)
+ # java.io.IOException
+ #
+ # (on Solaris so far, 1st sample)
+ # <pid>: Permission denied
+ #
+ sed 's/^/INFO: /' "$TEST_NAME.jmap"
+
+ if [ "$loop_cnt" = "$loop_cnt_on_retry" ]; then
+ # loop count hasn't changed
+ jmap_retry_cnt=`expr $jmap_retry_cnt + 1`
+ else
+ # loop count has changed so remember it
+ jmap_retry_cnt=1
+ loop_cnt_on_retry="$loop_cnt"
+ fi
+
+ # This is '-ge' because we have the original attempt plus
+ # MAX_JMAP_TRY_CNT - 1 retries.
+ if [ "$jmap_retry_cnt" -ge "$MAX_JMAP_TRY_CNT" ]; then
+ echo "INFO: jmap failed $MAX_JMAP_TRY_CNT times in a row" \
+ "without making any progress."
echo "FAIL: jmap is unable to take any samples." >&2
- echo "INFO: killing $test_pid"
- kill "$test_pid"
+ killApplication
exit 2
fi
- echo "INFO: The likely reason is that $TEST_NAME has finished running."
- break
+
+ # short delay and try again
+ # Note: sleep 1 didn't help with "<pid>: Permission denied"
+ sleep 2
+ echo "INFO: retrying jmap (retry=$jmap_retry_cnt, loop=$loop_cnt)."
+ continue
fi
- instance_cnt=`grep_cmd "[ ]$TARGET_CLASS$" \
- < "$TEST_NAME.jmap" \
+ set +e
+ instance_cnt=`grep "${PATTERN_WS}${TARGET_CLASS}${PATTERN_EOL}" \
+ "$TEST_NAME.jmap" \
| sed '
# strip leading whitespace; does nothing in JDK1.5.0
- s/^[ ][ ]*//
+ s/^'"${PATTERN_WS}${PATTERN_WS}"'*//
# strip <#bytes> in JDK1.5.0; does nothing otherwise
- s/^[1-9][0-9]*[ ][ ]*//
+ s/^[1-9][0-9]*'"${PATTERN_WS}${PATTERN_WS}"'*//
# strip <num>: field; does nothing in JDK1.5.0
- s/^[1-9][0-9]*:[ ][ ]*//
+ s/^[1-9][0-9]*:'"${PATTERN_WS}${PATTERN_WS}"'*//
# strip <class_name> field
- s/[ ].*//
+ s/'"${PATTERN_WS}"'.*//
'`
+ set -e
if [ -z "$instance_cnt" ]; then
echo "INFO: instance count is unexpectedly empty"
if [ "$loop_cnt" = 0 ]; then
@@ -211,8 +170,7 @@
cat "$TEST_NAME.jmap"
echo "INFO: end of jmap output."
echo "FAIL: cannot find the instance count value." >&2
- echo "INFO: killing $test_pid"
- kill "$test_pid"
+ killApplication
exit 2
fi
else
@@ -221,7 +179,17 @@
if [ "$instance_cnt" -gt "$prev_instance_cnt" ]; then
increasing_cnt=`expr $increasing_cnt + 1`
else
+ # actually decreasing or the same
decreasing_cnt=`expr $decreasing_cnt + 1`
+
+ # For these particular WeakReference leaks, the count was
+ # always observed to be increasing so if we get a decreasing
+ # or the same count, then the leaks are fixed in the bits
+ # being tested.
+ echo "INFO: finishing early due to non-increasing instance count."
+ finished_early=true
+ killApplication
+ break
fi
prev_instance_cnt="$instance_cnt"
fi
@@ -232,8 +200,22 @@
loop_cnt=`expr $loop_cnt + 1`
done
+if [ $finished_early = false ]; then
+ stopApplication "$TEST_NAME.port"
+ waitForApplication
+fi
+
+echo "INFO: $TEST_NAME has finished running."
echo "INFO: increasing_cnt = $increasing_cnt"
echo "INFO: decreasing_cnt = $decreasing_cnt"
+if [ "$jmap_retry_cnt" -gt 0 ]; then
+ echo "INFO: jmap_retry_cnt = $jmap_retry_cnt (in $loop_cnt iterations)"
+fi
+
+if [ "$loop_cnt" = 0 ]; then
+ echo "FAIL: jmap is unable to take any samples." >&2
+ exit 2
+fi
echo "INFO: The instance count of" `eval echo $TARGET_CLASS` "objects"
if [ "$decreasing_cnt" = 0 ]; then
@@ -242,6 +224,6 @@
exit 2
fi
-echo "INFO: is both increasing and decreasing."
+echo "INFO: is not always increasing."
echo "PASS: This indicates that there is not a memory leak."
exit 0
--- a/jdk/test/sun/tools/common/ApplicationSetup.sh Wed Jul 21 16:59:40 2010 -0700
+++ b/jdk/test/sun/tools/common/ApplicationSetup.sh Wed Jul 21 17:01:31 2010 -0700
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -24,54 +24,187 @@
#
-# Support function to start and stop a given application
+# Support functions to start, stop, wait for or kill a given SimpleApplication
-# Starts a given application as background process, usage:
-# startApplication <class> [args...]
+# Starts a given app as background process, usage:
+# startApplication <class> port-file [args...]
+#
+# The following variables are set:
#
-# Waits for application to print something to indicate it is running
-# (and initialized). Output is directed to ${TESTCLASSES}/Application.out.
-# Sets $pid to be the process-id of the application.
-
+# appJavaPid - application's Java pid
+# appOtherPid - pid associated with the app other than appJavaPid
+# appPidList - all pids associated with the app
+# appOutput - file containing stdout and stderr from the app
+#
+# Waits for at least one line of output from the app to indicate
+# that it is up and running.
+#
startApplication()
{
- OUTPUTFILE=${TESTCLASSES}/Application.out
- ${JAVA} $1 $2 $3 $4 $5 $6 > ${OUTPUTFILE} &
- pid="$!"
-
- # MKS creates an intermediate shell to launch ${JAVA} so
- # ${pid} is not the actual pid. We have put in a small sleep
- # to give the intermediate shell process time to launch the
- # "java" process.
- if [ "$OS" = "Windows" ]; then
- sleep 2
- if [ "${isCygwin}" = "true" ] ; then
- realpid=`ps -p ${pid} | tail -1 | awk '{print $4;}'`
- else
- realpid=`ps -o pid,ppid,comm|grep ${pid}|grep "java"|cut -c1-6`
- fi
- pid=${realpid}
- fi
-
- echo "Waiting for Application to initialize..."
- attempts=0
+ appOutput="${TESTCLASSES}/Application.out"
+
+ ${JAVA} -classpath "${TESTCLASSES}" "$@" > "$appOutput" 2>&1 &
+ appJavaPid="$!"
+ appOtherPid=
+ appPidList="$appJavaPid"
+
+ echo "INFO: waiting for $1 to initialize..."
+ _cnt=0
while true; do
+ # if the app doesn't start then the JavaTest/JTREG timeout will
+ # kick in so this isn't really a endless loop
sleep 1
- out=`tail -1 ${OUTPUTFILE}`
- if [ ! -z "$out" ]; then
+ out=`tail -1 "$appOutput"`
+ if [ -n "$out" ]; then
+ # we got some output from the app so it's running
break
fi
- attempts=`expr $attempts + 1`
- echo "Waiting $attempts second(s) ..."
+ _cnt=`expr $_cnt + 1`
+ echo "INFO: waited $_cnt second(s) ..."
done
+ unset _cnt
- echo "Application is process $pid"
+ if $isWindows; then
+ # Windows requires special handling
+ appOtherPid="$appJavaPid"
+
+ if $isCygwin; then
+ appJavaPid=`ps -p "$appOtherPid" \
+ | sed -n '
+ # See if $appOtherPid is in PID column; there are sometimes
+ # non-blanks in column 1 (I and S observed so far)
+ /^.'"${PATTERN_WS}${PATTERN_WS}*${appOtherPid}${PATTERN_WS}"'/{
+ # strip PID column
+ s/^.'"${PATTERN_WS}${PATTERN_WS}*${appOtherPid}${PATTERN_WS}${PATTERN_WS}"'*//
+ # strip PPID column
+ s/^[1-9][0-9]*'"${PATTERN_WS}${PATTERN_WS}"'*//
+ # strip PGID column
+ s/^[1-9][0-9]*'"${PATTERN_WS}${PATTERN_WS}"'*//
+ # strip everything after WINPID column
+ s/'"${PATTERN_WS}"'.*//
+ p
+ q
+ }
+ '`
+ echo "INFO: Cygwin pid=$appOtherPid maps to Windows pid=$appJavaPid"
+ else
+ # show PID, PPID and COMM columns only
+ appJavaPid=`ps -o pid,ppid,comm \
+ | sed -n '
+ # see if appOtherPid is in either PID or PPID columns
+ /'"${PATTERN_WS}${appOtherPid}${PATTERN_WS}"'/{
+ # see if this is a java command
+ /java'"${PATTERN_EOL}"'/{
+ # strip leading white space
+ s/^'"${PATTERN_WS}${PATTERN_WS}"'*//
+ # strip everything after the first word
+ s/'"${PATTERN_WS}"'.*//
+ # print the pid and we are done
+ p
+ q
+ }
+ }
+ '`
+ echo "INFO: MKS shell pid=$appOtherPid; Java pid=$appJavaPid"
+ fi
+
+ if [ -z "$appJavaPid" ]; then
+ echo "ERROR: could not find app's Java pid." >&2
+ killApplication
+ exit 2
+ fi
+ appPidList="$appOtherPid $appJavaPid"
+ fi
+
+ echo "INFO: $1 is process $appJavaPid"
+ echo "INFO: $1 output is in $appOutput"
+}
+
+
+# Stops a simple application by invoking ShutdownSimpleApplication
+# class with a specific port-file, usage:
+# stopApplication port-file
+#
+# Note: When this function returns, the SimpleApplication (or a subclass)
+# may still be running because the application has not yet reached the
+# shutdown check.
+#
+stopApplication()
+{
+ $JAVA -classpath "${TESTCLASSES}" ShutdownSimpleApplication $1
}
-# Stops an application by invoking the given class and argument, usage:
-# stopApplication <class> <argument>
-stopApplication()
-{
- $JAVA -classpath "${TESTCLASSES}" $1 $2
+
+# Wait for a simple application to stop running.
+#
+waitForApplication() {
+ if [ $isWindows = false ]; then
+ # non-Windows is easy; just one process
+ echo "INFO: waiting for $appJavaPid"
+ set +e
+ wait "$appJavaPid"
+ set -e
+
+ elif $isCygwin; then
+ # Cygwin pid and not the Windows pid
+ echo "INFO: waiting for $appOtherPid"
+ set +e
+ wait "$appOtherPid"
+ set -e
+
+ else # implied isMKS
+ # MKS has intermediate shell and Java process
+ echo "INFO: waiting for $appJavaPid"
+
+ # appJavaPid can be empty if pid search in startApplication() failed
+ if [ -n "$appJavaPid" ]; then
+ # only need to wait for the Java process
+ set +e
+ wait "$appJavaPid"
+ set -e
+ fi
+ fi
}
+
+# Kills a simple application by sending a SIGTERM to the appropriate
+# process(es); on Windows SIGQUIT (-9) is used.
+#
+killApplication()
+{
+ if [ $isWindows = false ]; then
+ # non-Windows is easy; just one process
+ echo "INFO: killing $appJavaPid"
+ set +e
+ kill -TERM "$appJavaPid" # try a polite SIGTERM first
+ sleep 2
+ # send SIGQUIT (-9) just in case SIGTERM didn't do it
+ # but don't show any complaints
+ kill -QUIT "$appJavaPid" > /dev/null 2>&1
+ wait "$appJavaPid"
+ set -e
+
+ elif $isCygwin; then
+ # Cygwin pid and not the Windows pid
+ echo "INFO: killing $appOtherPid"
+ set +e
+ kill -9 "$appOtherPid"
+ wait "$appOtherPid"
+ set -e
+
+ else # implied isMKS
+ # MKS has intermediate shell and Java process
+ echo "INFO: killing $appPidList"
+ set +e
+ kill -9 $appPidList
+ set -e
+
+ # appJavaPid can be empty if pid search in startApplication() failed
+ if [ -n "$appJavaPid" ]; then
+ # only need to wait for the Java process
+ set +e
+ wait "$appJavaPid"
+ set -e
+ fi
+ fi
+}
--- a/jdk/test/sun/tools/common/CommonSetup.sh Wed Jul 21 16:59:40 2010 -0700
+++ b/jdk/test/sun/tools/common/CommonSetup.sh Wed Jul 21 17:01:31 2010 -0700
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -24,56 +24,94 @@
#
-# Common setup for tool tests.
+# Common setup for tool tests and other tests that use jtools.
# Checks that TESTJAVA, TESTSRC, and TESTCLASSES environment variables are set.
-# Creates the following for use by the tool tests
-# JAVA java launcher
-# JSTACK jstack utility
-# JMAP jmap utility
-# JINFO jinfo utility
-# JHAT jhat utility
-# PS path separator (";" or ":")
-# OS operating system
+#
+# Creates the following constants for use by the caller:
+# JAVA - java launcher
+# JHAT - jhat utility
+# JINFO - jinfo utility
+# JMAP - jmap utility
+# JPS - jps utility
+# JSTACK - jstack utility
+# OS - operating system name
+# PATTERN_EOL - grep or sed end-of-line pattern
+# PATTERN_WS - grep or sed whitespace pattern
+# PS - path separator (";" or ":")
+#
+# Sets the following variables:
+#
+# isCygwin - true if environment is Cygwin
+# isMKS - true if environment is MKS
+# isLinux - true if OS is Linux
+# isSolaris - true if OS is Solaris
+# isWindows - true if OS is Windows
-if [ "${TESTJAVA}" = "" ]
-then
- echo "TESTJAVA not set. Test cannot execute. Failed."
+if [ -z "${TESTJAVA}" ]; then
+ echo "ERROR: TESTJAVA not set. Test cannot execute. Failed."
exit 1
fi
-
-if [ "${TESTSRC}" = "" ]
-then
- echo "TESTSRC not set. Test cannot execute. Failed."
+
+if [ -z "${TESTSRC}" ]; then
+ echo "ERROR: TESTSRC not set. Test cannot execute. Failed."
+ exit 1
+fi
+
+if [ -z "${TESTCLASSES}" ]; then
+ echo "ERROR: TESTCLASSES not set. Test cannot execute. Failed."
exit 1
fi
-
-if [ "${TESTCLASSES}" = "" ]
-then
- echo "TESTCLASSES not set. Test cannot execute. Failed."
- exit 1
-fi
-
+
+# only enable these after checking the expected incoming env variables
+set -eu
+
JAVA="${TESTJAVA}/bin/java"
-JSTACK="${TESTJAVA}/bin/jstack"
+JHAT="${TESTJAVA}/bin/jhat"
+JINFO="${TESTJAVA}/bin/jinfo"
JMAP="${TESTJAVA}/bin/jmap"
-JINFO="${TESTJAVA}/bin/jinfo"
-JHAT="${TESTJAVA}/bin/jhat"
+JPS="${TESTJAVA}/bin/jps"
+JSTACK="${TESTJAVA}/bin/jstack"
+
+isCygwin=false
+isMKS=false
+isLinux=false
+isSolaris=false
+isUnknownOS=false
+isWindows=false
OS=`uname -s`
+# start with some UNIX like defaults
+PATTERN_EOL='$'
+# blank and tab
+PATTERN_WS='[ ]'
+PS=":"
+
case "$OS" in
- Windows* )
- PS=";"
+ CYGWIN* )
OS="Windows"
+ PATTERN_EOL='[
]*$'
+ # blank and tab
+ PATTERN_WS='[ \t]'
+ isCygwin=true
+ isWindows=true
;;
- CYGWIN* )
+ Linux )
+ OS="Linux"
+ isLinux=true
+ ;;
+ SunOS )
+ OS="Solaris"
+ isSolaris=true
+ ;;
+ Windows* )
+ OS="Windows"
+ PATTERN_EOL='[
]*$'
PS=";"
- OS="Windows"
- isCygwin=true
+ isWindows=true
;;
* )
- PS=":"
+ isUnknownOS=true
;;
esac
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/tools/common/CommonTests.sh Wed Jul 21 17:01:31 2010 -0700
@@ -0,0 +1,314 @@
+#!/bin/sh
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code 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 General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+
+# @test
+# @bug 6964018
+# @summary Unit test for common tools infrastructure.
+#
+# @build SimpleApplication SleeperApplication ShutdownSimpleApplication
+# @run shell CommonTests.sh
+
+. ${TESTSRC}/CommonSetup.sh
+. ${TESTSRC}/ApplicationSetup.sh
+
+# hope for the best:
+status=0
+
+
+# Test program path constants from CommonSetup.sh:
+#
+for name in JAVA JHAT JINFO JMAP JPS JSTACK; do
+ eval value=$`echo $name`
+
+ echo "INFO: $name=$value"
+ if [ -x "$value" ]; then
+ echo "INFO: '$value' is executable."
+ else
+ echo "ERROR: '$value' is not executable." >&2
+ status=1
+ fi
+done
+
+
+# Display flag values from CommonSetup.sh:
+#
+for name in isCygwin isMKS isLinux isSolaris isUnknownOS isWindows; do
+ eval value=$`echo $name`
+ echo "INFO: flag $name=$value"
+done
+
+
+# Test OS constant from CommonSetup.sh:
+#
+if [ -z "$OS" ]; then
+ echo "ERROR: OS constant cannot be empty." >&2
+ status=1
+fi
+
+
+# Display the PATTERN_EOL value:
+#
+echo "INFO: PATTERN_EOL="`echo "$PATTERN_EOL" | od -c`
+
+
+# Test PATTERN_EOL with 'grep' for a regular line.
+#
+TESTOUT="${TESTCLASSES}/testout.grep_reg_line_eol"
+set +e
+echo 'regular line' | grep "line${PATTERN_EOL}" > "$TESTOUT"
+set -e
+if [ -s "$TESTOUT" ]; then
+ echo "INFO: PATTERN_EOL works for regular line with grep."
+else
+ echo "ERROR: PATTERN_EOL does not work for regular line with grep." >&2
+ status=1
+fi
+
+
+if $isWindows; then
+ # Test PATTERN_EOL with 'grep' for a CR line.
+ #
+ TESTOUT="${TESTCLASSES}/testout.grep_cr_line_eol"
+ set +e
+ echo 'CR line
' | grep "line${PATTERN_EOL}" > "$TESTOUT"
+ set -e
+ if [ -s "$TESTOUT" ]; then
+ echo "INFO: PATTERN_EOL works for CR line with grep."
+ else
+ echo "ERROR: PATTERN_EOL does not work for CR line with grep." >&2
+ status=1
+ fi
+fi
+
+
+# Test PATTERN_EOL with 'sed' for a regular line.
+#
+TESTOUT="${TESTCLASSES}/testout.sed_reg_line_eol"
+echo 'regular line' | sed -n "/line${PATTERN_EOL}/p" > "$TESTOUT"
+if [ -s "$TESTOUT" ]; then
+ echo "INFO: PATTERN_EOL works for regular line with sed."
+else
+ echo "ERROR: PATTERN_EOL does not work for regular line with sed." >&2
+ status=1
+fi
+
+
+if $isWindows; then
+ # Test PATTERN_EOL with 'sed' for a CR line.
+ #
+ TESTOUT="${TESTCLASSES}/testout.sed_cr_line_eol"
+ echo 'CR line
' | sed -n "/line${PATTERN_EOL}/p" > "$TESTOUT"
+ if [ -s "$TESTOUT" ]; then
+ echo "INFO: PATTERN_EOL works for CR line with sed."
+ else
+ echo "ERROR: PATTERN_EOL does not work for CR line with sed." >&2
+ status=1
+ fi
+fi
+
+
+# Display the PATTERN_WS value:
+#
+echo "INFO: PATTERN_WS="`echo "$PATTERN_WS" | od -c`
+
+
+# Test PATTERN_WS with 'grep' for a blank.
+#
+TESTOUT="${TESTCLASSES}/testout.grep_blank"
+set +e
+echo 'blank: ' | grep "$PATTERN_WS" > "$TESTOUT"
+set -e
+if [ -s "$TESTOUT" ]; then
+ echo "INFO: PATTERN_WS works for blanks with grep."
+else
+ echo "ERROR: PATTERN_WS does not work for blanks with grep." >&2
+ status=1
+fi
+
+
+# Test PATTERN_WS with 'grep' for a tab.
+#
+TESTOUT="${TESTCLASSES}/testout.grep_tab"
+set +e
+echo 'tab: ' | grep "$PATTERN_WS" > "$TESTOUT"
+set -e
+if [ -s "$TESTOUT" ]; then
+ echo "INFO: PATTERN_WS works for tabs with grep."
+else
+ echo "ERROR: PATTERN_WS does not work for tabs with grep." >&2
+ status=1
+fi
+
+
+# Test PATTERN_WS with 'sed' for a blank.
+#
+TESTOUT="${TESTCLASSES}/testout.sed_blank"
+echo 'blank: ' | sed -n "/$PATTERN_WS/p" > "$TESTOUT"
+if [ -s "$TESTOUT" ]; then
+ echo "INFO: PATTERN_WS works for blanks with sed."
+else
+ echo "ERROR: PATTERN_WS does not work for blanks with sed." >&2
+ status=1
+fi
+
+
+# Test PATTERN_WS with 'sed' for a tab.
+#
+TESTOUT="${TESTCLASSES}/testout.sed_tab"
+echo 'tab: ' | sed -n "/$PATTERN_WS/p" > "$TESTOUT"
+if [ -s "$TESTOUT" ]; then
+ echo "INFO: PATTERN_WS works for tabs with sed."
+else
+ echo "ERROR: PATTERN_WS does not work for tabs with sed." >&2
+ status=1
+fi
+
+
+# Test startApplication and use PORTFILE for coordination
+# The app sleeps for 30 seconds.
+#
+PORTFILE="${TESTCLASSES}"/shutdown.port
+startApplication SleeperApplication "${PORTFILE}" 30
+
+
+# Test appJavaPid in "ps" cmd output.
+#
+TESTOUT="${TESTCLASSES}/testout.ps_app"
+set +e
+if $isCygwin; then
+ # On Cygwin, appJavaPid is the Windows pid for the Java process
+ # and appOtherPid is the Cygwin pid for the Java process.
+ ps -p "$appOtherPid" \
+ | grep "${PATTERN_WS}${appJavaPid}${PATTERN_WS}" > "$TESTOUT"
+else
+ # output only pid and comm columns to avoid mismatches
+ ps -eo pid,comm \
+ | grep "^${PATTERN_WS}*${appJavaPid}${PATTERN_WS}" > "$TESTOUT"
+fi
+set -e
+if [ -s "$TESTOUT" ]; then
+ echo "INFO: begin appJavaPid=$appJavaPid in 'ps' cmd output:"
+ cat "$TESTOUT"
+ echo "INFO: end appJavaPid=$appJavaPid in 'ps' cmd output."
+else
+ echo "ERROR: 'ps' cmd should show appJavaPid=$appJavaPid." >&2
+ status=1
+fi
+
+if [ -n "$appOtherPid" ]; then
+ # Test appOtherPid in "ps" cmd output, if we have one.
+ #
+ TESTOUT="${TESTCLASSES}/testout.ps_other"
+ set +e
+ if $isCygwin; then
+ ps -p "$appOtherPid" \
+ | grep "${PATTERN_WS}${appOtherPid}${PATTERN_WS}" > "$TESTOUT"
+ else
+ # output only pid and comm columns to avoid mismatches
+ ps -eo pid,comm \
+ | grep "^${PATTERN_WS}*${appOtherPid}${PATTERN_WS}" > "$TESTOUT"
+ fi
+ set -e
+ if [ -s "$TESTOUT" ]; then
+ echo "INFO: begin appOtherPid=$appOtherPid in 'ps' cmd output:"
+ cat "$TESTOUT"
+ echo "INFO: end appOtherPid=$appOtherPid in 'ps' cmd output."
+ else
+ echo "ERROR: 'ps' cmd should show appOtherPid=$appOtherPid." >&2
+ status=1
+ fi
+fi
+
+
+# Test stopApplication and PORTFILE for coordination
+#
+stopApplication "${PORTFILE}"
+
+
+# Test application still running after stopApplication.
+#
+# stopApplication just lets the app know that it can stop, but the
+# app might still be doing work. This test just demonstrates that
+# fact and doesn't fail if the app is already done.
+#
+TESTOUT="${TESTCLASSES}/testout.after_stop"
+set +e
+if $isCygwin; then
+ # On Cygwin, appJavaPid is the Windows pid for the Java process
+ # and appOtherPid is the Cygwin pid for the Java process.
+ ps -p "$appOtherPid" \
+ | grep "${PATTERN_WS}${appJavaPid}${PATTERN_WS}" > "$TESTOUT"
+else
+ # output only pid and comm columns to avoid mismatches
+ ps -eo pid,comm \
+ | grep "^${PATTERN_WS}*${appJavaPid}${PATTERN_WS}" > "$TESTOUT"
+fi
+set -e
+if [ -s "$TESTOUT" ]; then
+ echo "INFO: it is okay for appJavaPid=$appJavaPid to still be running" \
+ "after stopApplication() is called."
+ echo "INFO: begin 'after_stop' output:"
+ cat "$TESTOUT"
+ echo "INFO: end 'after_stop' output."
+fi
+
+
+# Test waitForApplication
+#
+# The app might already be gone so this function shouldn't generate
+# a fatal error in either call.
+#
+waitForApplication
+
+if [ $isWindows = false ]; then
+ # Windows can recycle pids quickly so we can't use this test there
+ TESTOUT="${TESTCLASSES}/testout.after_kill"
+ set +e
+ # output only pid and comm columns to avoid mismatches
+ ps -eo pid,comm \
+ | grep "^${PATTERN_WS}*${appJavaPid}${PATTERN_WS}" > "$TESTOUT"
+ set -e
+ if [ -s "$TESTOUT" ]; then
+ echo "ERROR: 'ps' cmd should not show appJavaPid." >&2
+ echo "ERROR: begin 'after_kill' output:" >&2
+ cat "$TESTOUT" >&2
+ echo "ERROR: end 'after_kill' output." >&2
+ status=1
+ else
+ echo "INFO: 'ps' cmd does not show appJavaPid after" \
+ "waitForApplication() is called."
+ fi
+fi
+
+
+# Test killApplication
+#
+# The app is already be gone so this function shouldn't generate
+# a fatal error.
+#
+killApplication
+
+exit $status
--- a/jdk/test/sun/tools/common/ShutdownSimpleApplication.java Wed Jul 21 16:59:40 2010 -0700
+++ b/jdk/test/sun/tools/common/ShutdownSimpleApplication.java Wed Jul 21 17:01:31 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -22,10 +22,13 @@
*/
/*
- *
+ * Used to shutdown SimpleApplication (or a subclass). The argument to
+ * this class is the name of a file that contains the TCP port number
+ * on which SimpleApplication (or a subclass) is listening.
*
- * Used to shutdown SimpleApplication. The argument to this class is
- * the TCP port number where SimpleApplication is listening.
+ * Note: When this program returns, the SimpleApplication (or a subclass)
+ * may still be running because the application has not yet reached the
+ * shutdown check.
*/
import java.net.Socket;
import java.net.InetSocketAddress;
@@ -35,6 +38,11 @@
public class ShutdownSimpleApplication {
public static void main(String args[]) throws Exception {
+ if (args.length != 1) {
+ throw new RuntimeException("Usage: ShutdownSimpleApplication" +
+ " port-file");
+ }
+
// read the (TCP) port number from the given file
File f = new File(args[0]);
@@ -42,21 +50,27 @@
byte b[] = new byte[8];
int n = fis.read(b);
if (n < 1) {
- throw new RuntimeException("Empty file");
+ throw new RuntimeException("Empty port-file");
}
fis.close();
String str = new String(b, 0, n, "UTF-8");
- System.out.println("Port number of application is: " + str);
+ System.out.println("INFO: Port number of SimpleApplication: " + str);
int port = Integer.parseInt(str);
// Now connect to the port (which will shutdown application)
- System.out.println("Connecting to port " + port +
- " to shutdown Application ...");
+ System.out.println("INFO: Connecting to port " + port +
+ " to shutdown SimpleApplication ...");
+ System.out.flush();
Socket s = new Socket();
s.connect( new InetSocketAddress(port) );
s.close();
+
+ System.out.println("INFO: done connecting to SimpleApplication.");
+ System.out.flush();
+
+ System.exit(0);
}
}
--- a/jdk/test/sun/tools/common/SimpleApplication.java Wed Jul 21 16:59:40 2010 -0700
+++ b/jdk/test/sun/tools/common/SimpleApplication.java Wed Jul 21 17:01:31 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -22,10 +22,12 @@
*/
/*
- *
+ * A simple application used by unit tests. The first argument to this
+ * class is the name of a file to which a TCP port number can be written.
*
- * A simple application used for tool unit tests. It does nothing else
- * bind to a TCP port and wait for a shutdown message.
+ * By default, this class does nothing other than bind to a TCP port,
+ * write the TCP port number to a file, and wait for an incoming connection
+ * in order to complete the application shutdown protocol.
*/
import java.net.Socket;
import java.net.ServerSocket;
@@ -33,25 +35,86 @@
import java.io.FileOutputStream;
public class SimpleApplication {
- public static void main(String args[]) throws Exception {
+ private static SimpleApplication myApp; // simple app or a subclass
+ private static String myAppName; // simple app name
+ private static int myPort; // coordination port #
+ private static ServerSocket mySS; // coordination socket
+
+ // protected so a subclass can extend it; not public so creation is
+ // limited.
+ protected SimpleApplication() {
+ // save simple app (or subclass) name for messages
+ myAppName = getClass().getName();
+ }
+
+ // return the simple application (or a subclass)
+ final public static SimpleApplication getMyApp() {
+ return myApp;
+ }
+
+ // set the simple application (for use by a subclass)
+ final public static void setMyApp(SimpleApplication _myApp) {
+ myApp = _myApp;
+ }
+
+ // execute the application finish protocol
+ final public void doMyAppFinish(String[] args) throws Exception {
+ System.out.println("INFO: " + myAppName + " is waiting on port: " +
+ myPort);
+ System.out.flush();
+
+ // wait for test harness to connect
+ Socket s = mySS.accept();
+ s.close();
+ mySS.close();
+
+ System.out.println("INFO: " + myAppName + " is shutting down.");
+ System.out.flush();
+ }
+
+ // execute the application start protocol
+ final public void doMyAppStart(String[] args) throws Exception {
+ if (args.length < 1) {
+ throw new RuntimeException("Usage: " + myAppName +
+ " port-file [arg(s)]");
+ }
+
// bind to a random port
- ServerSocket ss = new ServerSocket(0);
- int port = ss.getLocalPort();
+ mySS = new ServerSocket(0);
+ myPort = mySS.getLocalPort();
// Write the port number to the given file
File f = new File(args[0]);
FileOutputStream fos = new FileOutputStream(f);
- fos.write( Integer.toString(port).getBytes("UTF-8") );
+ fos.write( Integer.toString(myPort).getBytes("UTF-8") );
fos.close();
- System.out.println("Application waiting on port: " + port);
+ System.out.println("INFO: " + myAppName + " created socket on port: " +
+ myPort);
+ System.out.flush();
+ }
+
+ // execute the app work (subclass can override this)
+ public void doMyAppWork(String[] args) throws Exception {
+ }
+
+ public static void main(String[] args) throws Exception {
+ if (myApp == null) {
+ // create myApp since a subclass hasn't done so
+ myApp = new SimpleApplication();
+ }
+
+ myApp.doMyAppStart(args); // do the app start protocol
+
+ System.out.println("INFO: " + myAppName + " is calling doMyAppWork()");
+ System.out.flush();
+ myApp.doMyAppWork(args); // do the app work
+ System.out.println("INFO: " + myAppName + " returned from" +
+ " doMyAppWork()");
System.out.flush();
- // wait for test harness to connect
- Socket s = ss.accept();
- s.close();
- ss.close();
+ myApp.doMyAppFinish(args); // do the app finish protocol
- System.out.println("Application shutdown.");
+ System.exit(0);
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/tools/common/SleeperApplication.java Wed Jul 21 17:01:31 2010 -0700
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * An example subclass of SimpleApplication that illustrates how to
+ * override the doMyAppWork() method.
+ */
+
+public class SleeperApplication extends SimpleApplication {
+ public static int DEFAULT_SLEEP_TIME = 60; // time is in seconds
+
+ // execute the sleeper app work
+ public void doMyAppWork(String[] args) throws Exception {
+ int sleep_time = DEFAULT_SLEEP_TIME;
+
+ // args[0] is the port-file
+ if (args.length < 2) {
+ System.out.println("INFO: using default sleep time of "
+ + sleep_time + " seconds.");
+ } else {
+ try {
+ sleep_time = Integer.parseInt(args[1]);
+ } catch (NumberFormatException nfe) {
+ throw new RuntimeException("Error: '" + args[1] +
+ "': is not a valid seconds value.");
+ }
+ }
+
+ Thread.sleep(sleep_time * 1000); // our "work" is to sleep
+ }
+
+ public static void main(String[] args) throws Exception {
+ SleeperApplication myApp = new SleeperApplication();
+
+ SimpleApplication.setMyApp(myApp);
+
+ SimpleApplication.main(args);
+ }
+}
--- a/jdk/test/sun/tools/jhat/ParseTest.sh Wed Jul 21 16:59:40 2010 -0700
+++ b/jdk/test/sun/tools/jhat/ParseTest.sh Wed Jul 21 17:01:31 2010 -0700
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,11 @@
# @run shell ParseTest.sh
. ${TESTSRC}/../common/CommonSetup.sh
-. ${TESTSRC}/../common/ApplicationSetup.sh
+
+# all return statuses are checked in this test
+set +e
+
+failed=0
DUMPFILE="minimal.bin"
--- a/jdk/test/sun/tools/jinfo/Basic.sh Wed Jul 21 16:59:40 2010 -0700
+++ b/jdk/test/sun/tools/jinfo/Basic.sh Wed Jul 21 17:01:31 2010 -0700
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -35,53 +35,57 @@
. ${TESTSRC}/../common/CommonSetup.sh
. ${TESTSRC}/../common/ApplicationSetup.sh
-# Start application (send output to shutdown.port)
+# Start application and use PORTFILE for coordination
PORTFILE="${TESTCLASSES}"/shutdown.port
-startApplication \
- -classpath "${TESTCLASSES}" SimpleApplication "${PORTFILE}"
+startApplication SimpleApplication "${PORTFILE}"
+
+# all return statuses are checked in this test
+set +e
failed=0
-if [ "$OS" != "Windows" ]; then
+if [ $isWindows = false ]; then
# -sysprops option
- ${JINFO} -sysprops $pid
+ ${JINFO} -sysprops $appJavaPid
if [ $? != 0 ]; then failed=1; fi
# -flags option
- ${JINFO} -flags $pid
+ ${JINFO} -flags $appJavaPid
if [ $? != 0 ]; then failed=1; fi
# no option
- ${JINFO} $pid
+ ${JINFO} $appJavaPid
if [ $? != 0 ]; then failed=1; fi
fi
# -flag option
-${JINFO} -flag +PrintGC $pid
+${JINFO} -flag +PrintGC $appJavaPid
if [ $? != 0 ]; then failed=1; fi
-${JINFO} -flag -PrintGC $pid
+${JINFO} -flag -PrintGC $appJavaPid
if [ $? != 0 ]; then failed=1; fi
-${JINFO} -flag PrintGC $pid
+${JINFO} -flag PrintGC $appJavaPid
if [ $? != 0 ]; then failed=1; fi
-if [ "$OS" = "SunOS" ]; then
+if $isSolaris; then
- ${JINFO} -flag +ExtendedDTraceProbes $pid
+ ${JINFO} -flag +ExtendedDTraceProbes $appJavaPid
if [ $? != 0 ]; then failed=1; fi
- ${JINFO} -flag -ExtendedDTraceProbes $pid
+ ${JINFO} -flag -ExtendedDTraceProbes $appJavaPid
if [ $? != 0 ]; then failed=1; fi
- ${JINFO} -flag ExtendedDTraceProbes $pid
+ ${JINFO} -flag ExtendedDTraceProbes $appJavaPid
if [ $? != 0 ]; then failed=1; fi
fi
-stopApplication ShutdownSimpleApplication "${PORTFILE}"
+set -e
+
+stopApplication "${PORTFILE}"
+waitForApplication
exit $failed
-
--- a/jdk/test/sun/tools/jmap/Basic.sh Wed Jul 21 16:59:40 2010 -0700
+++ b/jdk/test/sun/tools/jmap/Basic.sh Wed Jul 21 17:01:31 2010 -0700
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -35,24 +35,25 @@
. ${TESTSRC}/../common/CommonSetup.sh
. ${TESTSRC}/../common/ApplicationSetup.sh
-# Start application (send output to shutdown.port)
+# Start application and use PORTFILE for coordination
PORTFILE="${TESTCLASSES}"/shutdown.port
-startApplication \
- -classpath "${TESTCLASSES}" SimpleApplication "${PORTFILE}"
+startApplication SimpleApplication "${PORTFILE}"
+
+# all return statuses are checked in this test
+set +e
failed=0
# -histo[:live] option
-${JMAP} -histo $pid
+${JMAP} -histo $appJavaPid
if [ $? != 0 ]; then failed=1; fi
-${JMAP} -histo:live $pid
+${JMAP} -histo:live $appJavaPid
if [ $? != 0 ]; then failed=1; fi
# -dump option
-p=`expr $pid`
-DUMPFILE="java_pid${p}.hprof"
-${JMAP} -dump:format=b,file=${DUMPFILE} $pid
+DUMPFILE="java_pid${appJavaPid}.hprof"
+${JMAP} -dump:format=b,file=${DUMPFILE} $appJavaPid
if [ $? != 0 ]; then failed=1; fi
# check that heap dump is parsable
@@ -63,7 +64,7 @@
rm ${DUMPFILE}
# -dump:live option
-${JMAP} -dump:live,format=b,file=${DUMPFILE} $pid
+${JMAP} -dump:live,format=b,file=${DUMPFILE} $appJavaPid
if [ $? != 0 ]; then failed=1; fi
# check that heap dump is parsable
@@ -71,9 +72,11 @@
if [ $? != 0 ]; then failed=1; fi
# dump file is large so remove it
-rm ${DUMPFILE}
+rm -f ${DUMPFILE}
-stopApplication ShutdownSimpleApplication "${PORTFILE}"
+set -e
+
+stopApplication "${PORTFILE}"
+waitForApplication
exit $failed
-
--- a/jdk/test/sun/tools/jstack/Basic.sh Wed Jul 21 16:59:40 2010 -0700
+++ b/jdk/test/sun/tools/jstack/Basic.sh Wed Jul 21 17:01:31 2010 -0700
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -35,22 +35,26 @@
. ${TESTSRC}/../common/CommonSetup.sh
. ${TESTSRC}/../common/ApplicationSetup.sh
-# Start application (send output to shutdown.port)
+# Start application and use PORTFILE for coordination
PORTFILE="${TESTCLASSES}"/shutdown.port
-startApplication \
- -classpath "${TESTCLASSES}" SimpleApplication "${PORTFILE}"
+startApplication SimpleApplication "${PORTFILE}"
+
+# all return statuses are checked in this test
+set +e
failed=0
# normal
-$JSTACK $pid 2>&1
+$JSTACK $appJavaPid 2>&1
if [ $? != 0 ]; then failed=1; fi
# long
-$JSTACK -l $pid 2>&1
+$JSTACK -l $appJavaPid 2>&1
if [ $? != 0 ]; then failed=1; fi
-stopApplication ShutdownSimpleApplication "${PORTFILE}"
+set -e
+
+stopApplication "${PORTFILE}"
+waitForApplication
exit $failed
-