lucene-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Dawid Weiss <dawid.we...@gmail.com>
Subject Fwd: [concurrency-interest] _interrupted field visibility bug in OpenJDK 7+
Date Thu, 08 Nov 2012 07:38:49 GMT
Thought you'd be interested. I don't think it affects us but it's good
to know about it. Reproduces for me all the time on newer hotspots.

New (invisible) bug entry is at:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8003135

Dawid


---------- Forwarded message ----------
From: Dr Heinz M. Kabutz <heinz@javaspecialists.eu>
Date: Wed, Nov 7, 2012 at 11:00 PM
Subject: [concurrency-interest] _interrupted field visibility bug in OpenJDK 7+
To: concurrency-interest@cs.oswego.edu


During a hands-on session today of my new Concurrency Specialist
Course, one of my students discovered what we think might be an
interesting and potentially serious bug in the JVM.  It seems that the
Server HotSpot in OpenJDK 7 may sometimes hoist the value of the
_interrupted field.  This is interesting, since the value is not
stored in Java, but rather in the OSThread.hpp file in the jint
_interrupted field.  It is also pretty serious, because it means we
cannot rely on the interrupted status in order to shut down threads.
This will affect Future.cancel(), ExecutorService.shutdownNow() and a
whole bunch of other mechanisms that use interruptions to
cooperatively cancel tasks.  (Obviously the exercise was more involved
than the code presented in this email, after all the course is aimed
at intermediate to advanced Java developers.  So please don't expect
that this won't happen in your code - I've just taken away unnecessary
code until we can see the bug without any of the paraphernalia that
might distract.)

First off, some code that works as expected.  As soon as you interrupt
the thread, it breaks out of the while() loop and exits:

   public void think() {
       while (true) {
           if (Thread.currentThread().isInterrupted()) break;
       }
       System.out.println("We're done thinking");
   }

However, if you extract the "Thread.currentThread().isInterrupted()"
into a separate method, then that might be optimized by HotSpot to
always return false and the code then never ends:

   public void think() {
       while (true) {
           if (checkInterruptedStatus()) break;
       }
       System.out.println("We're done thinking");
   }

   private boolean checkInterruptedStatus() {
       return Thread.currentThread().isInterrupted();
   }

My assumption is that the checkInterruptedStatus() method is
aggressively optimized and then the actual status is not read again.
This does not happen with the client hotspot and also not with Java
1.6.0_37.  It does happen with the 1.8 EA that I've got on my MacBook
Pro.  The student was using a Windows machine, so this not just a Mac
problem.
Here is the complete code:

public class InterruptedVisibilityTest {
   public void think() {
       while (true) {
           if (checkInterruptedStatus()) break;
       }
       System.out.println("We're done thinking");
   }

   private boolean checkInterruptedStatus() {
       return Thread.currentThread().isInterrupted();
   }

   public static void main(String[] args) throws InterruptedException {
       final InterruptedVisibilityTest test =
               new InterruptedVisibilityTest();
       Thread thinkerThread = new Thread("Thinker") {
           public void run() {
               test.think();
           }
       };
       thinkerThread.start();
       Thread.sleep(500);
       thinkerThread.interrupt();
       long timeOfInterruption = System.currentTimeMillis();
       thinkerThread.join(500);
       if (thinkerThread.isAlive()) {
           System.err.println("Thinker did not shut down within 500ms");
           System.err.println("Error in Java Virtual Machine!");
           System.err.println("Interrupted: " + thinkerThread.isInterrupted());
           System.err.println();
           System.err.println("(Let's see if the thread ever dies and
how long it takes)");
           while (thinkerThread.isAlive()) {
               thinkerThread.join(1000);
               if (thinkerThread.isAlive()) {
                   System.err.println("  ... still waiting");
               }
           }
       }
       System.err.println("Finally, the thread has died - that took " +
               (System.currentTimeMillis() - timeOfInterruption) + "ms");
   }
}

As I said, the original code was more involved, but this demonstrates
the essentials.  I hope some of you might be able to take a look at
what's going on.

Regards

Heinz
--
Dr Heinz M. Kabutz (PhD CompSci)
Author of "The Java(tm) Specialists' Newsletter"
Sun Java Champion
IEEE Certified Software Development Professional
http://www.javaspecialists.eu
Tel: +30 69 75 595 262
Skype: kabutz


_______________________________________________
Concurrency-interest mailing list
Concurrency-interest@cs.oswego.edu
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@lucene.apache.org
For additional commands, e-mail: dev-help@lucene.apache.org


Mime
View raw message