6863420: os::javaTimeNanos() go backward on Solaris x86
Summary: Use new atomic long load method Atomic::load() to load max_hrtime.
Reviewed-by: never, ysr, johnc, phh, dcubed, acorn
--- a/hotspot/src/os/solaris/vm/os_solaris.cpp Sun Jul 26 12:59:41 2009 -0700
+++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Sun Jul 26 16:40:14 2009 -0700
@@ -1643,7 +1643,8 @@
inline hrtime_t getTimeNanos() {
if (VM_Version::supports_cx8()) {
const hrtime_t now = gethrtime();
- const hrtime_t prev = max_hrtime;
+ // Use atomic long load since 32-bit x86 uses 2 registers to keep long.
+ const hrtime_t prev = Atomic::load((volatile jlong*)&max_hrtime);
if (now <= prev) return prev; // same or retrograde time;
const hrtime_t obsv = Atomic::cmpxchg(now, (volatile jlong*)&max_hrtime, prev);
assert(obsv >= prev, "invariant"); // Monotonicity
--- a/hotspot/src/os_cpu/solaris_sparc/vm/atomic_solaris_sparc.inline.hpp Sun Jul 26 12:59:41 2009 -0700
+++ b/hotspot/src/os_cpu/solaris_sparc/vm/atomic_solaris_sparc.inline.hpp Sun Jul 26 16:40:14 2009 -0700
@@ -46,6 +46,8 @@
inline void Atomic::dec_ptr(volatile intptr_t* dest) { (void)add_ptr(-1, dest); }
inline void Atomic::dec_ptr(volatile void* dest) { (void)add_ptr(-1, dest); }
+inline jlong Atomic::load(volatile jlong* src) { return *src; }
+
#ifdef _GNU_SOURCE
inline jint Atomic::add (jint add_value, volatile jint* dest) {
--- a/hotspot/src/os_cpu/solaris_x86/vm/atomic_solaris_x86.inline.hpp Sun Jul 26 12:59:41 2009 -0700
+++ b/hotspot/src/os_cpu/solaris_x86/vm/atomic_solaris_x86.inline.hpp Sun Jul 26 16:40:14 2009 -0700
@@ -99,6 +99,8 @@
return (void*)_Atomic_cmpxchg_long((jlong)exchange_value, (volatile jlong*)dest, (jlong)compare_value, (int) os::is_MP());
}
+inline jlong Atomic::load(volatile jlong* src) { return *src; }
+
#else // !AMD64
inline intptr_t Atomic::add_ptr(intptr_t add_value, volatile intptr_t* dest) {
@@ -131,6 +133,15 @@
inline void* Atomic::cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value) {
return (void*)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value);
}
+
+extern "C" void _Atomic_load_long(volatile jlong* src, volatile jlong* dst);
+
+inline jlong Atomic::load(volatile jlong* src) {
+ volatile jlong dest;
+ _Atomic_load_long(src, &dest);
+ return dest;
+}
+
#endif // AMD64
#ifdef _GNU_SOURCE
--- a/hotspot/src/os_cpu/solaris_x86/vm/solaris_x86_32.il Sun Jul 26 12:59:41 2009 -0700
+++ b/hotspot/src/os_cpu/solaris_x86/vm/solaris_x86_32.il Sun Jul 26 16:40:14 2009 -0700
@@ -97,6 +97,15 @@
popl %ebx
.end
+ // Support for void Atomic::load(volatile jlong* src, volatile jlong* dest).
+ .inline _Atomic_load_long,2
+ movl 0(%esp), %eax // src
+ fildll (%eax)
+ movl 4(%esp), %eax // dest
+ fistpll (%eax)
+ .end
+
+
// Support for OrderAccess::acquire()
.inline _OrderAccess_acquire,0
movl 0(%esp), %eax
--- a/hotspot/src/share/vm/runtime/atomic.hpp Sun Jul 26 12:59:41 2009 -0700
+++ b/hotspot/src/share/vm/runtime/atomic.hpp Sun Jul 26 16:40:14 2009 -0700
@@ -39,6 +39,8 @@
static void store_ptr(intptr_t store_value, volatile intptr_t* dest);
static void store_ptr(void* store_value, volatile void* dest);
+ static jlong load(volatile jlong* src);
+
// Atomically add to a location, return updated value
static jint add (jint add_value, volatile jint* dest);
static intptr_t add_ptr(intptr_t add_value, volatile intptr_t* dest);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6863420/Test.java Sun Jul 26 16:40:14 2009 -0700
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2009 D.E. Shaw. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+/**
+ * @test
+ * @bug 6863420
+ * @summary os::javaTimeNanos() go backward on Solaris x86
+ *
+ * @run main/othervm Test
+ */
+
+public class Test {
+ static long value = 0;
+ static boolean got_backward_time = false;
+
+ public static void main(String args[]) {
+ final int count = 100000;
+
+ for (int numThreads = 1; numThreads <= 32; numThreads++) {
+ final int numRuns = 1;
+ for (int t=1; t <= numRuns; t++) {
+ final int curRun = t;
+
+ System.out.println("Spawning " + numThreads + " threads");
+ final Thread threads[] = new Thread[numThreads];
+ for (int i = 0; i < threads.length; i++) {
+ Runnable thread =
+ new Runnable() {
+ public void run() {
+ for (long l = 0; l < 100000; l++) {
+ final long start = System.nanoTime();
+ if (value == 12345678) {
+ System.out.println("Wow!");
+ }
+ final long end = System.nanoTime();
+ final long time = end - start;
+ value += time;
+ if (time < 0) {
+ System.out.println(
+ "Backwards: " +
+ "start=" + start + " " +
+ "end=" + end + " " +
+ "time= " + time
+ );
+ got_backward_time = true;
+ }
+ }
+ }
+ };
+ threads[i] = new Thread(thread, "Thread" + i);
+ }
+ for (int i = 0; i < threads.length; i++) {
+ threads[i].start();
+ }
+ for (int i = 0; i < threads.length; i++) {
+ try {
+ threads[i].join();
+ }
+ catch (InterruptedException e) {
+ continue;
+ }
+ }
+ }
+ }
+
+ if (got_backward_time) {
+ System.exit(97);
+ }
+ }
+}