This commit is contained in:
Alejandro Murillo 2015-02-03 08:45:07 -08:00
commit 004b407992
25 changed files with 769 additions and 83 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015, 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
@ -61,12 +61,15 @@
*/
package java.time;
import java.io.IOException;
import java.io.ObjectInputStream;
import static java.time.LocalTime.NANOS_PER_MINUTE;
import static java.time.LocalTime.NANOS_PER_SECOND;
import java.io.Serializable;
import java.util.Objects;
import java.util.TimeZone;
import sun.misc.VM;
/**
* A clock providing access to the current instant, date and time using a time-zone.
@ -446,10 +449,22 @@ public abstract class Clock {
*/
static final class SystemClock extends Clock implements Serializable {
private static final long serialVersionUID = 6740630888130243051L;
private static final long OFFSET_SEED =
System.currentTimeMillis()/1000 - 1024; // initial offest
private final ZoneId zone;
// We don't actually need a volatile here.
// We don't care if offset is set or read concurrently by multiple
// threads - we just need a value which is 'recent enough' - in other
// words something that has been updated at least once in the last
// 2^32 secs (~136 years). And even if we by chance see an invalid
// offset, the worst that can happen is that we will get a -1 value
// from getNanoTimeAdjustment, forcing us to update the offset
// once again.
private transient long offset;
SystemClock(ZoneId zone) {
this.zone = zone;
this.offset = OFFSET_SEED;
}
@Override
public ZoneId getZone() {
@ -464,11 +479,50 @@ public abstract class Clock {
}
@Override
public long millis() {
// System.currentTimeMillis() and VM.getNanoTimeAdjustment(offset)
// use the same time source - System.currentTimeMillis() simply
// limits the resolution to milliseconds.
// So we take the faster path and call System.currentTimeMillis()
// directly - in order to avoid the performance penalty of
// VM.getNanoTimeAdjustment(offset) which is less efficient.
return System.currentTimeMillis();
}
@Override
public Instant instant() {
return Instant.ofEpochMilli(millis());
// Take a local copy of offset. offset can be updated concurrently
// by other threads (even if we haven't made it volatile) so we will
// work with a local copy.
long localOffset = offset;
long adjustment = VM.getNanoTimeAdjustment(localOffset);
if (adjustment == -1) {
// -1 is a sentinel value returned by VM.getNanoTimeAdjustment
// when the offset it is given is too far off the current UTC
// time. In principle, this should not happen unless the
// JVM has run for more than ~136 years (not likely) or
// someone is fiddling with the system time, or the offset is
// by chance at 1ns in the future (very unlikely).
// We can easily recover from all these conditions by bringing
// back the offset in range and retry.
// bring back the offset in range. We use -1024 to make
// it more unlikely to hit the 1ns in the future condition.
localOffset = System.currentTimeMillis()/1000 - 1024;
// retry
adjustment = VM.getNanoTimeAdjustment(localOffset);
if (adjustment == -1) {
// Should not happen: we just recomputed a new offset.
// It should have fixed the issue.
throw new InternalError("Offset " + localOffset + " is not in range");
} else {
// OK - recovery succeeded. Update the offset for the
// next call...
offset = localOffset;
}
}
return Instant.ofEpochSecond(localOffset, adjustment);
}
@Override
public boolean equals(Object obj) {
@ -485,6 +539,12 @@ public abstract class Clock {
public String toString() {
return "SystemClock[" + zone + "]";
}
private void readObject(ObjectInputStream is)
throws IOException, ClassNotFoundException {
// ensure that offset is initialized
is.defaultReadObject();
offset = OFFSET_SEED;
}
}
//-----------------------------------------------------------------------

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2015, 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
@ -57,6 +57,7 @@ import java.time.ZoneOffset;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalQueries;
import java.time.temporal.UnsupportedTemporalTypeException;
import sun.misc.DoubleConsts;
import sun.misc.FormattedFloatingDecimal;
@ -4056,7 +4057,12 @@ public final class Formatter implements Closeable, Flushable {
break;
}
case DateTime.NANOSECOND: { // 'N' (000000000 - 999999999)
int i = t.get(ChronoField.MILLI_OF_SECOND) * 1000000;
int i;
try {
i = t.get(ChronoField.NANO_OF_SECOND);
} catch (UnsupportedTemporalTypeException u) {
i = t.get(ChronoField.MILLI_OF_SECOND) * 1000000;
}
Flags flags = Flags.ZERO_PAD;
sb.append(localizedMagnitude(null, i, flags, 9, l));
break;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2015, 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
@ -402,6 +402,36 @@ public class VM {
*/
public static native long getegid();
/**
* Get a nanosecond time stamp adjustment in the form of a single long.
*
* This value can be used to create an instant using
* {@link java.time.Instant#ofEpochSecond(long, long)
* java.time.Instant.ofEpochSecond(offsetInSeconds,
* getNanoTimeAdjustment(offsetInSeconds))}.
* <p>
* The value returned has the best resolution available to the JVM on
* the current system.
* This is usually down to microseconds - or tenth of microseconds -
* depending on the OS/Hardware and the JVM implementation.
*
* @param offsetInSeconds The offset in seconds from which the nanosecond
* time stamp should be computed.
*
* @apiNote The offset should be recent enough - so that
* {@code offsetInSeconds} is within {@code +/- 2^32} seconds of the
* current UTC time. If the offset is too far off, {@code -1} will be
* returned. As such, {@code -1} must not be considered as a valid
* nano time adjustment, but as an exception value indicating
* that an offset closer to the current time should be used.
*
* @return A nanosecond time stamp adjustment in the form of a single long.
* If the offset is too far off the current time, this method returns -1.
* In that case, the caller should call this method again, passing a
* more accurate offset.
*/
public static native long getNanoTimeAdjustment(long offsetInSeconds);
static {
initialize();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2015, 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
@ -104,6 +104,9 @@ JVM_CurrentTimeMillis(JNIEnv *env, jclass ignored);
JNIEXPORT jlong JNICALL
JVM_NanoTime(JNIEnv *env, jclass ignored);
JNIEXPORT jlong JNICALL
JVM_GetNanoTimeAdjustment(JNIEnv *env, jclass ignored, jlong offset_secs);
JNIEXPORT void JNICALL
JVM_ArrayCopy(JNIEnv *env, jclass ignored, jobject src, jint src_pos,
jobject dst, jint dst_pos, jint length);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2004, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2004, 2015, 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
@ -33,6 +33,11 @@
#include "sun_misc_VM.h"
/* Only register the performance-critical methods */
static JNINativeMethod methods[] = {
{"getNanoTimeAdjustment", "(J)J", (void *)&JVM_GetNanoTimeAdjustment}
};
JNIEXPORT jobject JNICALL
Java_sun_misc_VM_latestUserDefinedLoader(JNIEnv *env, jclass cls) {
return JVM_LatestUserDefinedLoader(env);
@ -49,6 +54,14 @@ Java_sun_misc_VM_initialize(JNIEnv *env, jclass cls) {
return;
}
// Registers implementations of native methods described in methods[]
// above.
// In particular, registers JVM_GetNanoTimeAdjustment as the implementation
// of the native sun.misc.VM.getNanoTimeAdjustment - avoiding the cost of
// introducing a Java_sun_misc_VM_getNanoTimeAdjustment wrapper
(*env)->RegisterNatives(env, cls,
methods, sizeof(methods)/sizeof(methods[0]));
func_p = (GetJvmVersionInfo_fp) JDK_FindJvmEntry("JVM_GetVersionInfo");
if (func_p != NULL) {
jvm_version_info info;

View File

@ -123,7 +123,6 @@
# 8029891
java/lang/ClassLoader/deadlock/GetResource.java generic-all
############################################################################
# jdk_instrument
@ -142,6 +141,9 @@ java/lang/instrument/BootClassPath/BootClassPathTest.sh macosx-all
# 8058492
java/lang/management/ThreadMXBean/FindDeadlocks.java generic-all
# 8069286
java/lang/management/MemoryMXBean/LowMemoryTest.java generic-all
############################################################################
# jdk_jmx
@ -296,15 +298,18 @@ com/sun/jdi/JdbMethodExitTest.sh generic-all
# 8043571
com/sun/jdi/RepStep.java generic-all
# 8044419
com/sun/jdi/JdbReadTwiceTest.sh generic-all
# 8058616
com/sun/jdi/RedefinePop.sh generic-all
# 8068645
com/sun/jdi/CatchPatternTest.sh generic-all
# 8069402
com/sun/jdi/ConnectedVMs.java generic-all
# 8067354
com/sun/jdi/GetLocalVariables4Test.sh windows-all
############################################################################
# jdk_util

View File

@ -92,7 +92,7 @@ fi
#
echo "JDK under test is: $TESTJAVA"
#
CP="-classpath ${TESTCLASSES}${PATHSEP}${TESTJAVA}/lib/tools.jar"
CP="-classpath ${TESTCLASSES}"
# Compile the test class using the classpath we need:
#
env

View File

@ -103,15 +103,15 @@ if [ -z "${TESTJAVA}" ] ; then
#if running standalone (no test harness of any kind), compile the
#support files and the test case
${TESTJAVA}/bin/javac -d ${TESTCLASSES} \
-classpath "$TESTJAVA/lib/tools.jar${PATHSEP}${TESTSRC}" \
-classpath "${TESTSRC}" \
TestScaffold.java VMConnection.java TargetListener.java TargetAdapter.java
${TESTJAVA}/bin/javac -d ${TESTCLASSES} \
-classpath "$TESTJAVA/lib/tools.jar${PATHSEP}${TESTSRC}" -g \
-classpath "${TESTSRC}" -g \
JITDebug.java
fi
echo "JDK under test is: $TESTJAVA"
#
CLASSPATH="$TESTJAVA/lib/tools.jar${PATHSEP}${TESTCLASSES}"
CLASSPATH="${TESTCLASSES}"
export CLASSPATH
CP="-classpath \"${CLASSPATH}\""
#

View File

@ -204,27 +204,37 @@ if [ ! -r c:/ ] ; then
clean
fi
echo
echo "+++++++++++++++++++++++++++++++++++"
echo "Read an unreadable file - verify the read fails."
if [ ! -r c:/ ] ; then
# Can't make a file unreadable under MKS.
echo
echo "+++++++++++++++++++++++++++++++++++"
echo "Read an unreadable file - verify the read fails."
# If the file exists, we try to read it. The
# read will fail.
mkFiles $HOME/jdb.ini
id > $HOME/jdb.ini
chmod a-r $HOME/jdb.ini
if grep -q "uid=" $HOME/jdb.ini ; then
echo "Unable to make file unreadable, so test will fail. chmod: $HOME/jdb.ini"
if grep -q "uid=0" $HOME/jdb.ini ; then
echo "The test is running as root. Fix infrastructure!"
fi
fi
canMakeUnreadable=No
id > $HOME/jdb.ini
if chmod a-r $HOME/jdb.ini
then
grep -q 'uid=0(' $HOME/jdb.ini 2> /dev/null
case $? in
0)
echo "Error! Can't make file unreadable running as root"
;;
1)
echo "Error! Can't make file unreadable for some other reason (windows?)"
;;
*)
echo "OK. the file is unreadable"
canMakeUnreadable=Yes
;;
esac
else
echo "Error! Can't create or chmod file"
fi
if [ "$canMakeUnreadable" = "Yes" ]
then
doit
failIfNot 1 "open: $HOME/jdb.ini"
clean
fi
clean
echo
@ -246,8 +256,8 @@ echo "read $fred" > $here/jdb.ini
doit
failIfNot 1 "from $fred"
if [ ! -r c:/ ] ; then
# Can't make a file unreadable under MKS
if [ "$canMakeUnreadable" = "Yes" ]
then
chmod a-r $fred
doit
failIfNot 1 "open: $fred"

View File

@ -22,9 +22,8 @@
*/
/*
* Creates a URLClassLoader from 2 file URLs. The first
* file URL is constructed from the given argument. The
* second is the SDK tools.jar. Once created the test
* Creates a URLClassLoader from a file URL. The file URL
* is constructed from the given argument. Once created the test
* attempts to load another test case (ListConnectors)
* using the class loader and then it invokes the list()
* method.
@ -39,13 +38,9 @@ public class JdiLoadedByCustomLoader {
public static void main(String args[]) throws Exception {
// create files from given arguments and tools.jar
File f1 = new File(args[0]);
String home = System.getProperty("java.home");
String tools = ".." + File.separatorChar + "lib" +
File.separatorChar + "tools.jar";
File f2 = (new File(home, tools)).getCanonicalFile();
// create class loader
URL[] urls = { f1.toURL(), f2.toURL() };
URL[] urls = { f1.toURL() };
URLClassLoader cl = new URLClassLoader(urls);
// load ListConnectors using the class loader

View File

@ -68,7 +68,7 @@ SOMEOTHERDIR="${TESTCLASSES}"/someotherdir
$JAVAC -d "${TESTCLASSES}" "${TESTSRC}"/JdiLoadedByCustomLoader.java
mkdir "${SOMEOTHERDIR}"
$JAVAC -d "${SOMEOTHERDIR}" -classpath "${TESTSRC}${PS}${TESTJAVA}/lib/tools.jar" \
$JAVAC -d "${SOMEOTHERDIR}" -classpath "${TESTSRC}" \
"${TESTSRC}"/ListConnectors.java
# Run the test

View File

@ -62,7 +62,7 @@ public class CheckOrigin {
"-XX:+UseConcMarkSweepGC", // this will cause UseParNewGC to be FLAG_SET_ERGO
"-XX:+PrintGCDetails",
"-XX:Flags=" + flagsFile.getAbsolutePath(),
"-cp", System.getProperty("test.class.path") + File.pathSeparator + getToolsJarPath(),
"-cp", System.getProperty("test.class.path"),
"CheckOrigin",
"-runtests");
@ -137,8 +137,4 @@ public class CheckOrigin {
vm.detach();
}
private static String getToolsJarPath() {
return System.getProperty("java.home") +
"/../lib/tools.jar".replace("/", File.separator);
}
}

View File

@ -80,8 +80,7 @@ public class BasicTests {
// Need to add jdk/lib/tools.jar to classpath.
String classpath =
System.getProperty("test.class.path", "") + File.pathSeparator +
System.getProperty("test.jdk", ".") + sep + "lib" + sep + "tools.jar";
System.getProperty("test.class.path", "");
String testClassDir = System.getProperty("test.classes", "") + sep;
// Argumenta : -classpath cp BasicTests$TestMain pid agent badagent redefineagent

View File

@ -71,10 +71,8 @@ public class PermissionTest {
private static void runTests(long pid) throws Throwable {
final String sep = File.separator;
// Need to add jdk/lib/tools.jar to classpath.
String classpath =
System.getProperty("test.class.path", "") + File.pathSeparator +
System.getProperty("test.jdk", ".") + sep + "lib" + sep + "tools.jar";
System.getProperty("test.class.path", "");
String testSrc = System.getProperty("test.src", "") + sep;
// Use a policy that will NOT allow attach. Test will verify exception.

View File

@ -68,11 +68,10 @@ public class ProviderTest {
String testClasses = System.getProperty("test.classes", "") + sep;
String jdkLib = System.getProperty("test.jdk", ".") + sep + "lib" + sep;
// Need to add SimpleProvider.jar and tools.jar to classpath.
// Need to add SimpleProvider.jar to classpath.
String classpath =
testClassPath + File.pathSeparator +
testClasses + "SimpleProvider.jar" + File.pathSeparator +
jdkLib + "tools.jar";
testClasses + "SimpleProvider.jar";
String[] args = {
"-classpath",

View File

@ -120,10 +120,8 @@ public class TempDirTest {
private static void launchTests(long pid, Path clientTmpDir) throws Throwable {
final String sep = File.separator;
// Need to add jdk/lib/tools.jar to classpath.
String classpath =
System.getProperty("test.class.path", "") + File.pathSeparator +
System.getProperty("test.jdk", ".") + sep + "lib" + sep + "tools.jar";
System.getProperty("test.class.path", "");
String[] tmpDirArg = null;
if (clientTmpDir != null) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2015, 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
@ -23,7 +23,6 @@
/**
* @test
* @ignore JDK-8068162
* @bug 6331574
* @summary test isModifiableClass
* @author Robert Field, Sun Microsystems

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015, 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
@ -292,7 +292,8 @@ public class TCKLocalDateTime extends AbstractDateTimeTest {
expected = LocalDateTime.now(Clock.system(zone));
test = LocalDateTime.now(zone);
}
assertEquals(test, expected);
assertEquals(test.truncatedTo(ChronoUnit.SECONDS),
expected.truncatedTo(ChronoUnit.SECONDS));
}
//-----------------------------------------------------------------------

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015, 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
@ -246,7 +246,8 @@ public class TCKLocalTime extends AbstractDateTimeTest {
expected = LocalTime.now(Clock.system(zone));
test = LocalTime.now(zone);
}
assertEquals(test, expected);
assertEquals(test.truncatedTo(ChronoUnit.SECONDS),
expected.truncatedTo(ChronoUnit.SECONDS));
}
//-----------------------------------------------------------------------

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015, 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
@ -260,7 +260,8 @@ public class TCKZonedDateTime extends AbstractDateTimeTest {
expected = ZonedDateTime.now(Clock.system(zone));
test = ZonedDateTime.now(zone);
}
assertEquals(test, expected);
assertEquals(test.truncatedTo(ChronoUnit.SECONDS),
expected.truncatedTo(ChronoUnit.SECONDS));
}
//-----------------------------------------------------------------------

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015, 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
@ -62,7 +62,9 @@ package test.java.time;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertSame;
import java.lang.reflect.Field;
import java.time.Clock;
import java.time.Instant;
import java.time.ZoneId;
import org.testng.annotations.Test;
@ -87,4 +89,298 @@ public class TestClock_System {
assertEquals(test.toString(), "SystemClock[Europe/Paris]");
}
//-----------------------------------------------------------------------
private static String formatTime(String prefix, Instant time) {
return prefix + ": " + time + " - seconds: "
+ time.getEpochSecond() + ", nanos: "
+ time.getNano();
}
public void test_ClockResolution() {
Clock highestUTC = Clock.systemUTC();
Instant start = Instant.ofEpochMilli(System.currentTimeMillis());
try {
// smoke test
Instant system1 = Instant.ofEpochMilli(System.currentTimeMillis());
Instant system2 = Instant.ofEpochMilli(System.currentTimeMillis());
Instant highest1 = highestUTC.instant();
Instant highest2 = highestUTC.instant();
System.out.println(formatTime("\nsystemUTC #1 ", system1));
System.out.println(formatTime("systemUTC #2 ", system2));
System.out.println(formatTime("highestResolutionUTC #1 ", highest1));
System.out.println(formatTime("highestResolutionUTC #2 ", highest2));
if (system2.isBefore(system1)) {
System.err.println("system2 is before system1!");
System.err.println(formatTime("\n\tsystem1", system1));
System.err.println(formatTime("\n\tsystem2", system2));
throw new RuntimeException("system2 is before system1!"
+ formatTime("\n\tsystem1", system1)
+ formatTime("\n\tsystem2", system2));
}
if (highest2.isBefore(highest1)) {
System.err.println("highest2 is before highest1!");
System.err.println(formatTime("\n\thighest1", system1));
System.err.println(formatTime("\n\tsystem2", highest2));
throw new RuntimeException("highest2 is before system1!"
+ formatTime("\n\thighest1", system1)
+ formatTime("\n\tsystem2", highest2));
}
// better test - but depends on implementation details.
// we're not rounding - so highest1 should be greater or equal to
// system1
system1 = Instant.ofEpochMilli(System.currentTimeMillis());
highest1 = highestUTC.instant();
System.out.println(formatTime("\nsystemUTC ", system1));
System.out.println(formatTime("highestResolutionUTC ", highest1));
if (highest1.isBefore(system1)) {
System.err.println("highest1 is before system1!");
System.err.println(formatTime("\n\tsystem1", system1));
System.err.println(formatTime("\n\thighest1", highest1));
throw new RuntimeException("highest1 is before system1!"
+ formatTime("\n\tsystem1", system1)
+ formatTime("\n\thighest1", highest1));
}
int count=0;
// let's preheat the system a bit:
for (int i = 0; i < 1000 ; i++) {
system1 = Instant.ofEpochMilli(System.currentTimeMillis());
highest1 = highestUTC.instant();
final int sysnan = system1.getNano();
final int nanos = highest1.getNano();
if ((nanos % 1000000) > 0) {
count++; // we have micro seconds
}
if ((sysnan % 1000000) > 0) {
throw new RuntimeException("Expected only millisecconds "
+ "precision for systemUTC, found "
+ (sysnan % 1000000) + " remainder.");
}
}
System.out.println("\nNumber of time stamps which had better than"
+ " millisecond precision: "+count+"/"+1000);
System.out.println(formatTime("\nsystemUTC ", system1));
System.out.println(formatTime("highestResolutionUTC ", highest1));
if (count == 0) {
System.err.println("Something is strange: no microsecond "
+ "precision with highestResolutionUTC?");
throw new RuntimeException("Micro second preccision not reached");
}
// check again
if (highest1.isBefore(system1)) {
System.err.println("highest1 is before system1!");
System.err.println(formatTime("\n\tsystem1", system1));
System.err.println(formatTime("\n\thighest1", highest1));
throw new RuntimeException("highest1 is before system1!"
+ formatTime("\n\tsystem1", system1)
+ formatTime("\n\thighest1", highest1));
}
// leap of faith: ensure that highest1 is from within 10 secs of
// system1
if (highest1.toEpochMilli() != system1.toEpochMilli()) {
long delta = highest1.getEpochSecond() - system1.getEpochSecond();
if (delta > 10) {
throw new RuntimeException("Unexpected long delay between two clocks ("
+ delta + " seconds)"
+ formatTime("\n\t system1", system1)
+ formatTime("\n\t highest1", highest1));
}
} else {
System.out.println("You won the lottery: the two dates are within 1 millisecond!\n");
}
} finally {
Instant stop = Instant.ofEpochMilli(System.currentTimeMillis());
if (start.isAfter(stop)) {
// This should not happen - but can (un)probably be observed
// when switching to summer time, or if another application
// is switching the system date...
System.err.println("Cannot test - date was setback: "
+ formatTime("\n\tstarted at", start)
+ formatTime("\n\tstopped at", stop) + "\n");
return; // will prevent exceptions from being propagated.
}
}
}
static final long MAX_OFFSET = 0x0100000000L;
static final long MIN_OFFSET = -MAX_OFFSET;
// A helper class to test that SystemClock correctly recomputes
// its offset.
static class SystemClockOffset {
static final int MILLIS_IN_SECOND = 1000;
static final int NANOS_IN_MILLI = 1000_000;
static final int NANOS_IN_MICRO = 1000;
static final int NANOS_IN_SECOND = 1000_000_000;
static final boolean verbose = true;
static final Clock systemUTC = Clock.systemUTC();
static final Field offsetField;
static {
try {
offsetField = Class.forName("java.time.Clock$SystemClock").getDeclaredField("offset");
offsetField.setAccessible(true);
} catch (ClassNotFoundException | NoSuchFieldException ex) {
throw new ExceptionInInitializerError(ex);
}
}
static enum Answer {
YES, // isOffLimit = YES: we must get -1
NO, // isOffLimit = NO: we must not not get -1
MAYBE // isOffLimit = MAYBE: we might get -1 or a valid adjustment.
};
static long distance(long one, long two) {
return one > two ? Math.subtractExact(one, two)
: Math.subtractExact(two, one);
}
static Answer isOffLimits(long before, long after, long offset) {
long relativeDistanceBefore = distance(before, offset);
long relativeDistanceAfter = distance(after, offset);
if (relativeDistanceBefore >= MAX_OFFSET && relativeDistanceAfter >= MAX_OFFSET) {
return Answer.YES;
}
if (relativeDistanceBefore < MAX_OFFSET && relativeDistanceAfter < MAX_OFFSET) {
if (relativeDistanceBefore == 0 || relativeDistanceAfter == 0) {
return Answer.MAYBE; // unlucky case where
}
return Answer.NO;
}
return Answer.MAYBE;
}
static void testWithOffset(String name, long offset)
throws IllegalAccessException {
testWithOffset(name, offset, systemUTC);
}
static void testWithOffset(String name, long offset, Clock clock)
throws IllegalAccessException {
offsetField.set(clock, offset);
long beforeMillis = System.currentTimeMillis();
final Instant instant = clock.instant();
long afterMillis = System.currentTimeMillis();
long actualOffset = offsetField.getLong(clock);
long instantMillis = instant.getEpochSecond() * MILLIS_IN_SECOND
+ instant.getNano() / NANOS_IN_MILLI;
if (instantMillis < beforeMillis || instantMillis > afterMillis) {
throw new RuntimeException(name
+ ": Invalid instant: " + instant
+ " (~" + instantMillis + "ms)"
+ " when time in millis is in ["
+ beforeMillis + ", " + afterMillis
+ "] and offset in seconds is " + offset);
}
Answer isOffLimits = isOffLimits(beforeMillis / MILLIS_IN_SECOND,
afterMillis / MILLIS_IN_SECOND, offset);
switch (isOffLimits) {
case YES:
if (actualOffset == offset) {
throw new RuntimeException(name
+ ": offset was offlimit but was not recomputed "
+ " when time in millis is in ["
+ beforeMillis + ", " + afterMillis
+ "] and offset in seconds was " + offset);
}
break;
case NO:
if (actualOffset != offset) {
throw new RuntimeException(name
+ ": offset was not offlimit but was recomputed.");
}
break;
default:
break;
}
if (distance(actualOffset, instant.getEpochSecond()) >= MAX_OFFSET) {
throw new RuntimeException(name + ": Actual offset is too far off:"
+ " offset=" + actualOffset
+ "instant.seconds=" + instant.getEpochSecond());
}
long adjustment = (instant.getEpochSecond() - actualOffset) * NANOS_IN_SECOND
+ instant.getNano();
validateAdjustment(name, actualOffset, beforeMillis, afterMillis, adjustment);
}
static void validateAdjustment(String name, long offset, long beforeMillis,
long afterMillis, long adjustment) {
System.out.println("Validating adjustment: " + adjustment);
long expectedMax = distance(offset, beforeMillis / MILLIS_IN_SECOND)
* NANOS_IN_SECOND
+ (beforeMillis % MILLIS_IN_SECOND) * NANOS_IN_MILLI
+ (afterMillis - beforeMillis + 1) * NANOS_IN_MILLI;
long absoluteAdjustment = distance(0, adjustment);
if (absoluteAdjustment > expectedMax) {
long adjSec = absoluteAdjustment / NANOS_IN_SECOND;
long adjMil = (absoluteAdjustment % NANOS_IN_SECOND) / NANOS_IN_MILLI;
long adjMic = (absoluteAdjustment % NANOS_IN_MILLI) / NANOS_IN_MICRO;
long adjNan = (absoluteAdjustment % NANOS_IN_MICRO);
long expSec = expectedMax / NANOS_IN_SECOND;
long expMil = (expectedMax % NANOS_IN_SECOND) / NANOS_IN_MILLI;
long expMic = (expectedMax % NANOS_IN_MILLI) / NANOS_IN_MICRO;
long expNan = (expectedMax % NANOS_IN_MICRO);
System.err.println("Excessive adjustment: " + adjSec + "s, "
+ adjMil + "ms, " + adjMic + "mics, " + adjNan + "ns");
System.err.println("Epected max: " + expSec + "s, "
+ expMil + "ms, " + expMic + "mics, " + expNan + "ns");
throw new RuntimeException(name
+ ": Excessive adjustment: " + adjustment
+ " when time in millis is in ["
+ beforeMillis + ", " + afterMillis
+ "] and offset in seconds is " + offset);
}
}
}
public void test_OffsetRegular() throws IllegalAccessException {
System.out.println("*** Testing regular cases ***");
SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000",
System.currentTimeMillis()/1000);
SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 - 1024",
System.currentTimeMillis()/1000 - 1024);
SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 + 1024",
System.currentTimeMillis()/1000 + 1024);
}
public void test_OffsetLimits() throws IllegalAccessException {
System.out.println("*** Testing limits ***");
SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 - MAX_OFFSET + 1",
System.currentTimeMillis()/1000 - MAX_OFFSET + 1);
SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 + MAX_OFFSET - 1",
System.currentTimeMillis()/1000 + MAX_OFFSET - 1);
SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 - MAX_OFFSET",
System.currentTimeMillis()/1000 - MAX_OFFSET);
SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 + MAX_OFFSET",
System.currentTimeMillis()/1000 + MAX_OFFSET);
SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 - MAX_OFFSET - 1024",
System.currentTimeMillis()/1000 - MAX_OFFSET - 1024);
SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 + MAX_OFFSET + 1024",
System.currentTimeMillis()/1000 + MAX_OFFSET + 1024);
SystemClockOffset.testWithOffset("0", 0);
SystemClockOffset.testWithOffset("-1", -1);
SystemClockOffset.testWithOffset("Integer.MAX_VALUE + System.currentTimeMillis()/1000",
((long)Integer.MAX_VALUE) + System.currentTimeMillis()/1000);
SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 - Integer.MIN_VALUE",
System.currentTimeMillis()/1000 - Integer.MIN_VALUE);
SystemClockOffset.testWithOffset("Long.MAX_VALUE", Long.MAX_VALUE);
SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 - Long.MIN_VALUE",
(Long.MIN_VALUE + System.currentTimeMillis()/1000)*-1);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015, 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
@ -38,6 +38,7 @@ import java.time.chrono.Chronology;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalQueries;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.util.*;
@ -153,6 +154,44 @@ public class TestFormatter {
if (verbose) {
System.out.printf("%-24s : %s%n", getClassName(dt), out);
}
// expected usually comes from Calendar which only has milliseconds
// precision. So we're going to replace it's N:[nanos] stamp with
// the correct value for nanos.
if ((dt instanceof TemporalAccessor) && expected != null) {
try {
// Get millis & nanos from the dt
final TemporalAccessor ta = (TemporalAccessor) dt;
final int nanos = ta.get(ChronoField.NANO_OF_SECOND);
final int millis = ta.get(ChronoField.MILLI_OF_SECOND);
final String nanstr = String.valueOf(nanos);
final String mistr = String.valueOf(millis);
// Compute the value of the N:[nanos] field that we expect
// to find in 'out'
final StringBuilder sb = new StringBuilder();
sb.append("N:[");
for (int i=nanstr.length(); i<9; i++) {
sb.append('0');
}
sb.append(nanos).append("]");
// Compute the truncated value of N:[nanos] field that might
// be in 'expected' when expected was built from Calendar.
final StringBuilder sbm = new StringBuilder();
sbm.append("N:[");
for (int i=mistr.length(); i<3; i++) {
sbm.append('0');
}
sbm.append(mistr).append("000000]");
// if expected contains the truncated value, replace it with
// the complete value.
expected = expected.replace(sbm.toString(), sb.toString());
} catch (UnsupportedTemporalTypeException e) {
// nano seconds unsupported - nothing to do...
}
}
if (expected != null && !out.equals(expected)) {
System.out.printf("%-24s actual: %s%n FAILED; expected: %s%n",
getClassName(dt), out, expected);

View File

@ -145,13 +145,7 @@ public class CustomLauncherTest {
ProcessBuilder client = ProcessTools.createJavaProcessBuilder(
"-cp",
TEST_CLASSPATH +
File.pathSeparator +
TEST_JDK +
File.separator +
"lib" +
File.separator +
"tools.jar",
TEST_CLASSPATH,
"TestManager",
String.valueOf(serverPrc.getPid()),
port.get(),

View File

@ -132,13 +132,7 @@ public class LocalManagementTest {
ProcessBuilder client = ProcessTools.createJavaProcessBuilder(
"-cp",
TEST_CLASSPATH +
File.pathSeparator +
TEST_JDK +
File.separator +
"lib" +
File.separator +
"tools.jar",
TEST_CLASSPATH,
"TestManager",
String.valueOf(serverPrc.getPid()),
port.get(),

View File

@ -0,0 +1,249 @@
/*
* Copyright (c) 2015, 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.
*/
import java.util.Objects;
import sun.misc.VM;
/**
* @test
* @bug 8068730
* @summary tests that VM.getgetNanoTimeAdjustment() works as expected.
* @run main GetNanoTimeAdjustment
* @author danielfuchs
*/
public class GetNanoTimeAdjustment {
static final int MILLIS_IN_SECOND = 1000;
static final int NANOS_IN_MILLI = 1000_000;
static final int NANOS_IN_MICRO = 1000;
static final int NANOS_IN_SECOND = 1000_000_000;
static final boolean verbose = true;
static final class TestAssertException extends RuntimeException {
TestAssertException(String msg) { super(msg); }
}
private static void assertEquals(long expected, long received, String msg) {
if (expected != received) {
throw new TestAssertException("Unexpected result for " + msg
+ ".\n\texpected: " + expected
+ "\n\tactual: " + received);
} else if (verbose) {
System.out.println("Got expected " + msg + ": " + received);
}
}
private static void assertEquals(Object expected, Object received, String msg) {
if (!Objects.equals(expected, received)) {
throw new TestAssertException("Unexpected result for " + msg
+ ".\n\texpected: " + expected
+ "\n\tactual: " + received);
} else if (verbose) {
System.out.println("Got expected " + msg + ": " + received);
}
}
static final long MAX_OFFSET = 0x0100000000L;
static final long MIN_OFFSET = -MAX_OFFSET;
static enum Answer {
YES, // isOffLimit = YES: we must get -1
NO, // isOffLimit = NO: we must not not get -1
MAYBE // isOffLimit = MAYBE: we might get -1 or a valid adjustment.
};
static long distance(long one, long two) {
return one > two ? Math.subtractExact(one, two)
: Math.subtractExact(two, one);
}
static Answer isOffLimits(long before, long after, long offset) {
long relativeDistanceBefore = distance(before, offset);
long relativeDistanceAfter = distance(after, offset);
if (relativeDistanceBefore >= MAX_OFFSET && relativeDistanceAfter >= MAX_OFFSET) {
return Answer.YES;
}
if (relativeDistanceBefore < MAX_OFFSET && relativeDistanceAfter < MAX_OFFSET) {
if (relativeDistanceBefore == 0 || relativeDistanceAfter == 0) {
return Answer.MAYBE; // unlucky case where
}
return Answer.NO;
}
return Answer.MAYBE;
}
static void testWithOffset(String name, long offset) {
System.out.println("Testing with offset: " + name);
long beforeMillis = System.currentTimeMillis();
long adjustment = VM.getNanoTimeAdjustment(offset);
long afterMillis = System.currentTimeMillis();
if (offset >= beforeMillis/MILLIS_IN_SECOND
&& offset <= afterMillis/MILLIS_IN_SECOND) {
if (adjustment == -1) {
// it's possible that we have fallen in the unlucky case
// where -1 was the genuine result. let's go backward a bit.
offset = offset - 10;
beforeMillis = System.currentTimeMillis();
adjustment = VM.getNanoTimeAdjustment(offset);
afterMillis = System.currentTimeMillis();
if (adjustment == -1) {
throw new RuntimeException(name + ": VM says " + offset
+ " secs is too far off, "
+ " when time in seconds is in ["
+ beforeMillis/MILLIS_IN_SECOND + ", "
+ afterMillis/MILLIS_IN_SECOND
+ "]");
}
}
}
Answer isOffLimit = isOffLimits(beforeMillis/MILLIS_IN_SECOND,
afterMillis/MILLIS_IN_SECOND, offset);
switch (isOffLimit) {
case YES:
if (adjustment != -1) {
throw new RuntimeException(name
+ ": VM should have returned -1 for "
+ offset
+ " when time in seconds is in ["
+ beforeMillis/MILLIS_IN_SECOND + ", "
+ afterMillis/MILLIS_IN_SECOND + "]");
}
System.out.println("Got expected exception value: " + adjustment);
break;
case NO:
if (adjustment == -1) {
throw new RuntimeException(name
+ "VM says " + offset
+ " secs is too far off, "
+ " when time in seconds is in ["
+ beforeMillis/MILLIS_IN_SECOND + ", "
+ afterMillis/MILLIS_IN_SECOND
+ "]");
}
break;
case MAYBE:
System.out.println("Adjustment: " + adjustment);
System.out.println("Can't assert for -1 with offset "
+ offset + "(" + name + ")"
+ " when time in seconds is in ["
+ beforeMillis/MILLIS_IN_SECOND + ", "
+ afterMillis/MILLIS_IN_SECOND
+ "]");
// not conclusive
}
if (isOffLimit == Answer.NO || adjustment != -1) {
System.out.println("Validating adjustment: " + adjustment);
long expectedMax = distance(offset, beforeMillis/MILLIS_IN_SECOND)
* NANOS_IN_SECOND
+ (beforeMillis % MILLIS_IN_SECOND) * NANOS_IN_MILLI
+ (afterMillis - beforeMillis + 1) * NANOS_IN_MILLI;
long absoluteAdjustment = distance(0, adjustment);
if (absoluteAdjustment > expectedMax) {
long adjSec = absoluteAdjustment / NANOS_IN_SECOND;
long adjMil = (absoluteAdjustment % NANOS_IN_SECOND) / NANOS_IN_MILLI;
long adjMic = (absoluteAdjustment % NANOS_IN_MILLI) / NANOS_IN_MICRO;
long adjNan = (absoluteAdjustment % NANOS_IN_MICRO);
long expSec = expectedMax / NANOS_IN_SECOND;
long expMil = (expectedMax % NANOS_IN_SECOND) / NANOS_IN_MILLI;
long expMic = (expectedMax % NANOS_IN_MILLI) / NANOS_IN_MICRO;
long expNan = (expectedMax % NANOS_IN_MICRO);
System.err.println("Excessive adjustment: " + adjSec + "s, "
+ adjMil + "ms, " + adjMic + "mics, " + adjNan + "ns");
System.err.println("Epected max: " + expSec + "s, "
+ expMil + "ms, " + expMic + "mics, " + expNan + "ns");
throw new RuntimeException(name
+ ": Excessive adjustment: " + adjustment
+ " when time in millis is in ["
+ beforeMillis + ", " + afterMillis
+ "] and offset in seconds is " + offset);
}
}
}
static void regular() {
System.out.println("*** Testing regular cases ***");
final long start = System.currentTimeMillis();
long offset = start/1000;
long adjustment = VM.getNanoTimeAdjustment(offset);
if (start != offset*1000) {
if (adjustment == -1) {
throw new RuntimeException("VM says " + offset
+ " secs is too far off, but time millis is "
+ System.currentTimeMillis());
}
}
if (adjustment == -1) {
offset = System.currentTimeMillis()/1000 - 1024;
adjustment = VM.getNanoTimeAdjustment(offset);
if (adjustment == -1) {
throw new RuntimeException("VM says " + offset
+ " secs is too far off, but time millis is "
+ System.currentTimeMillis());
}
}
if (adjustment > (start/1000 - offset + 20)*NANOS_IN_SECOND) {
throw new RuntimeException("Excessive adjustment: " + adjustment);
}
testWithOffset("System.currentTimeMillis()/1000",
System.currentTimeMillis()/1000);
testWithOffset("System.currentTimeMillis()/1000 - 1024",
System.currentTimeMillis()/1000 - 1024);
testWithOffset("System.currentTimeMillis()/1000 + 1024",
System.currentTimeMillis()/1000 + 1024);
}
static void testLimits() {
System.out.println("*** Testing limits ***");
testWithOffset("System.currentTimeMillis()/1000 - MAX_OFFSET + 1",
System.currentTimeMillis()/1000 - MAX_OFFSET + 1);
testWithOffset("System.currentTimeMillis()/1000 + MAX_OFFSET - 1",
System.currentTimeMillis()/1000 + MAX_OFFSET - 1);
testWithOffset("System.currentTimeMillis()/1000 - MAX_OFFSET",
System.currentTimeMillis()/1000 - MAX_OFFSET);
testWithOffset("System.currentTimeMillis()/1000 + MAX_OFFSET",
System.currentTimeMillis()/1000 + MAX_OFFSET);
testWithOffset("System.currentTimeMillis()/1000 - MAX_OFFSET - 1024",
System.currentTimeMillis()/1000 - MAX_OFFSET - 1024);
testWithOffset("System.currentTimeMillis()/1000 + MAX_OFFSET + 1024",
System.currentTimeMillis()/1000 + MAX_OFFSET + 1024);
testWithOffset("0", 0);
testWithOffset("-1", -1);
testWithOffset("Integer.MAX_VALUE + System.currentTimeMillis()/1000",
((long)Integer.MAX_VALUE) + System.currentTimeMillis()/1000);
testWithOffset("System.currentTimeMillis()/1000 - Integer.MIN_VALUE",
System.currentTimeMillis()/1000 - Integer.MIN_VALUE);
testWithOffset("Long.MAX_VALUE", Long.MAX_VALUE);
testWithOffset("System.currentTimeMillis()/1000 - Long.MIN_VALUE",
(Long.MIN_VALUE + System.currentTimeMillis()/1000)*-1);
}
public static void main(String[] args) throws Exception {
regular();
testLimits();
}
}