Merge
This commit is contained in:
commit
004b407992
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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}\""
|
||||
#
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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",
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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(),
|
||||
|
@ -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(),
|
||||
|
249
jdk/test/sun/misc/VM/GetNanoTimeAdjustment.java
Normal file
249
jdk/test/sun/misc/VM/GetNanoTimeAdjustment.java
Normal 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();
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user