Thursday, March 4, 2010

System.nanoTime() does not always return a value greater than the previous call

 
-----Original Message-----
From: IncidentDaemon@sun.com [mailto:IncidentDaemon@sun.com]
Sent: Wednesday, October 14, 2009 1:52 PM
To: John Amos
Subject: Your Report (Review ID: 1630000) - System.nanoTime() does not always return a value greater than the previous call

************************************************
Dear Java Developer,

Thank you for your interest in improving the quality of Java Technology.

Your report has been assigned an internal review ID of 1630000, which is NOT visible on the Sun Developer Network (SDN).

Please be aware that the large volume of reports we receive sometimes prevents us from responding individually to each message.

If the information is determined to be a new Bug or RFE, or a duplicate of a known Bug or RFE, you will receive a followup email containing a seven digit bug number.  You may search for, view, or vote for this bug in the Bug Database at http://bugs.sun.com/.

If you just reported an issue that could have a major impact on your project and require a timely response, please consider purchasing one of the support offerings described at http://developers.sun.com/services/.

The Sun Developer Network (http://developers.sun.com) is a free service that Sun offers. To join, visit http://developers.sun.com/global/join_sdn.html.

For a limited time, SDN members can obtain fully licensed Java IDEs for web and enterprise development.  More information is at http://developers.sun.com/prodtech/javatools/free/.

Thank you for using our bug submit page.

Regards,
Java Developer Bug Report Review Team



---------------------------------------------------------------


Date Created: Wed Oct 14 14:52:15 MDT 2009
Type:        rfe
Customer Name:   John Amos
Customer Email:  ***@****.***
SDN ID:      
status:      Waiting
Category:    java
Subcategory: classes_lang
Company:     ******
release:     5.0
hardware:    x86
OSversion:   windows_2003
priority:    4
Synopsis:    System.nanoTime() does not always return a value greater than the previous call
Description:
 A DESCRIPTION OF THE REQUEST :
On some systems with VMWare 2.5.x, the difference between two calls to System.nanoTime() is negative (t1 - t0 < 0).  AbstractQueuedSynchronizer assumes this will never happen.



JUSTIFICATION :
While it is valid to claim that this a defect in VMWare and/or Windows and/or the hardware, it is also irrelevant.  System.nanoTime() should be written defensively, so that it can never return a value that is less than the value from the previous call.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
System.nanoTime() should never return a value that is less than the value from the previous call.  If that isn't possible on the host platform, then this method should write an error message to the console.  The current behavior of failing silently is not acceptable.
ACTUAL -
Runnables that are in the queue of a ScheduledThreadPoolExecutor never run because AbstractQueuedSynchronizer.awaitNanos() is in an infinite loop.  I confirmed using a debugger that the expression (now - lastTime) in this method evaluates to a negative number.

---------- BEGIN SOURCE ----------
now - lastTime evaluates to a negative number in the following method from AbstractQueuedSynchronizer, which is used by ScheduledThreadPoolExecutor.

public final long awaitNanos(long nanosTimeout) throws InterruptedException {
            if (Thread.interrupted())
                throw new InterruptedException();
            Node node = addConditionWaiter();
            int savedState = fullyRelease(node);
            long lastTime = System.nanoTime();
            int interruptMode = 0;
            while (!isOnSyncQueue(node)) {
                if (nanosTimeout <= 0L) {
                    transferAfterCancelledWait(node);
                    break;
                }
                LockSupport.parkNanos(nanosTimeout);
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                    break;
                long now = System.nanoTime();
                nanosTimeout -= now - lastTime;
                lastTime = now;
            }
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                interruptMode = REINTERRUPT;
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);
            return nanosTimeout - (System.nanoTime() - lastTime);
}


---------- END SOURCE ----------
workaround: 
comments:   

No comments:

Post a Comment