JDK-6751923 : JNDI wake up when clock_settime() is called
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 5.0u13
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: solaris_10
  • CPU: sparc
  • Submitted: 2008-09-24
  • Updated: 2012-10-08
  • Resolved: 2009-12-03
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other JDK 6 JDK 7 Other
5.0u23,hs20Fixed 6u25Fixed 7Fixed hs20Fixed
Related Reports
Relates :  
Relates :  
Description
JNDI threads are not sleeping after another program calls clock_settime()  (Like NTP for Solaris does).

The test case is below, one C program mimics the behavior of NTP to use clock_settime() to change the time (just incase your NTP is up to date, so the clock doesn't actually change with NTP). The other program uses Java and JNDI. I guess this problem happens with both 5u13 and 6u7 jvms.

Here's the code:
The C program below uses this function below to emulate NTP behavior. So, you
can also use NTP as the trigger as long as you can get it "step" the
time.

#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
   struct timeval currTime;
   struct timespec tp;

   if (argc < 2){
       perror("Command: SetSysTime interval\n");
       return 1;
   }
   int interval = atoi(argv[1]);


   printf("Adjusting system time...\n");
   int ret = clock_gettime(CLOCK_REALTIME, &tp);
   if (ret == 0)
       printf("System time retrieved successfully: %d \n", tp.tv_sec);
   else
       printf("System time NOT retrieved successfully\n");

   tp.tv_sec += interval;
   ret = clock_settime(CLOCK_REALTIME, &tp);
   if (ret == 0)
       printf("System time was set successfully\n");
   else
       printf("System time was NOT set successfully\n");

   printf("System time was adjusted by %d sec\n", interval);
}


If you run the above program  to adjust system clock, then you
enter something as the input to the 2nd program below so that it
continues. You can see the code executed right after your input will
wake up other sleeping threads prematurely. You can run the 2nd program
with a thread sleeping time longer (e.g. 180) to make the problem shown
more obviously. The 2nd program below is a java program. You will need
to update the line of looking up LDAP server with your own LDAP IP
address before compiling.

------- Start File TestSleep.java -------

import java.io.*;
import javax.naming.*;
import javax.naming.directory.*;


public class TestSleep implements Runnable {

  Thread mThread = null;
  DirContext dirContext = null;

  public TestSleep(){
    try{
      InitialContext mInitCtx = new InitialContext();
      dirContext =
(DirContext)mInitCtx.lookup("ldap://xxx.xxx.xxx.xxx:xxx/");
    } catch (Exception ex){
      ex.printStackTrace();
    }
      mThread = new Thread(this);
      mThread.start();
  }


  public void run(){
      System.out.println("New thread is running...");
      BufferedReader reader = new BufferedReader(new
InputStreamReader(System.in));
      try{
          System.out.println("Please enter something to kick off
context closing");
          String inStr = reader.readLine();
          System.out.println("Input Data: "+inStr);

          //including the line of code below will cause sleep waken up
          //taking out the line below will not cause sleep waken up
          dirContext.close();
      } catch (IOException ex){
          ex.printStackTrace();
      } catch (Exception ex){
          ex.printStackTrace();
      }

  }


  public static void main(String[] args){
      int val=0;
      TestSleep tester= null;
      try{
          tester = new TestSleep();
          System.out.println("Application starts now...");
          val = Integer.parseInt(args[0]);

          System.out.println("Main thread will sleep for "+val+"
seconds...");
          Thread.sleep(val*1000);
          System.out.println("Main thread finished sleep!");
      } catch (InterruptedException ex) {
          ex.printStackTrace();
      }

      System.out.println("Application ends now...");

  }
}

------- End of file ------- 

I searched your bug database before. There was a different, but very
similar, bug before. I think it was accepted as bug and noted to have
been fixed. My impression is it was filed against 1.4.x. 

But that bug was different from this one. As you said, that bug would
show up whenever you changed the system clock through NTP and it caused
the sleep() and wait() to wake up. I tried to follow that one in the
same testing environment I had for testing my bug. I was not able to
reproduce it. That means that bug was really fixed. 

For mine, you have to do a DirContext.close() to get the problem shown.
Without that line of code, it will not have any problem. 
You can use my test program to verify by simply commenting out the
close() line and you will not see it happen. 

From the test programs I provided, you can see that it does not have to
be NTP. As long as you make the system call through clock_settime() you
will see it. 

For the time being, we can do, actually we are doing, checking after the
sleeping threads waken up and make sure it has slept enough time.
Otherwise, we will put it back into sleep again. But as a general
design/implementation, you should not wake up because a directory
context is closed after system clock is adjusted. So, I can not buy that
as an acceptable behavior. 

If a thread can wake up on all different kinds of unknown conditions
prematurely, it will be very bad. Every time it wakes up it costs some
resources even if you do make additional checking. Unless you publish a
list of conditions which will cause the sleep() waken up before the
time, application developers will not be able to avoid those. Then
potentially, those waken up incidences can be VERY frequent. In that
case, it will dramatically downgrade its performance. Do you think Java
will still be a good business application development language? 

Unfortunately, I don't see any suggestions, in your API documentation
for sleep(), that the time set when calling sleep() is only a hint and
the thread can wake up any time for any unknown reasons. In my opinion,
if any public classes' public methods have variable behavior depending
on unknown conditions, its usefulness becomes very low since the users
do not know how to deal with them. This is like if you have an engineer
working for you and his behavior changes on many unknown conditions how
difficult task it will be for his manager to manage this unreliable
personnel.

Comments
EVALUATION http://hg.openjdk.java.net/jdk7/build/hotspot/rev/22260322f0be
25-12-2010

EVALUATION See suggested fix. We expand the rety logic for the interrupt (EINTR) case to also apply to the normal case (res == 0). This ensures that we check we have slept for at least the time requested.
18-11-2010

EVALUATION <moved to sub-CR>
18-11-2010

SUGGESTED FIX Change to jdk1.5.0u19 src/os/solaris/vm/os_solaris.cpp : 2c2 < #pragma ident "%W% %E% %U% JVM" --- > #pragma ident "@(#)os_solaris.cpp 1.344 08/08/06 09:54:17 JVM" 5c5 < * %W% %E% --- > * @(#)os_solaris.cpp 1.344 08/08/06 2677,2682c2677 < // See c/r 6751923. Poll can return 0 before time < // has elapsed if time is set via clock_settime (as NTP does). < // res == 0 if poll timed out (see man poll RETURN VALUES) < // using the logic below checks that we really did < // sleep at least "millis" if not we'll sleep again. < if( ( res == 0 ) || ((res == OS_ERR) && (errno == EINTR))) { --- > if((res == OS_ERR) && (errno == EINTR)) {
08-04-2009

EVALUATION The problem can be demonstrated on Solaris 10 using the 2 programs supplied in the bug description. However it does not occur on Linux (using Red Hat with either 2.4 or 2.6 kernel).
09-10-2008