# HG changeset patch # User kvn # Date 1248651614 25200 # Node ID 665be97e87043168e56742b8d58982dd15669d18 # Parent dd0a4e1e219be34f30b422eb1520ddcc1da13c27 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 diff -r dd0a4e1e219b -r 665be97e8704 src/os/solaris/vm/os_solaris.cpp --- a/src/os/solaris/vm/os_solaris.cpp Sun Jul 26 12:59:41 2009 -0700 +++ b/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 diff -r dd0a4e1e219b -r 665be97e8704 src/os_cpu/solaris_sparc/vm/atomic_solaris_sparc.inline.hpp --- a/src/os_cpu/solaris_sparc/vm/atomic_solaris_sparc.inline.hpp Sun Jul 26 12:59:41 2009 -0700 +++ b/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) { diff -r dd0a4e1e219b -r 665be97e8704 src/os_cpu/solaris_x86/vm/atomic_solaris_x86.inline.hpp --- a/src/os_cpu/solaris_x86/vm/atomic_solaris_x86.inline.hpp Sun Jul 26 12:59:41 2009 -0700 +++ b/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 diff -r dd0a4e1e219b -r 665be97e8704 src/os_cpu/solaris_x86/vm/solaris_x86_32.il --- a/src/os_cpu/solaris_x86/vm/solaris_x86_32.il Sun Jul 26 12:59:41 2009 -0700 +++ b/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 diff -r dd0a4e1e219b -r 665be97e8704 src/share/vm/runtime/atomic.hpp --- a/src/share/vm/runtime/atomic.hpp Sun Jul 26 12:59:41 2009 -0700 +++ b/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); diff -r dd0a4e1e219b -r 665be97e8704 test/compiler/6863420/Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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); + } + } +}