[concurrency-interest] _interrupted field visibility bug in OpenJDK 7+

Vitaly Davidovich vitalyd at gmail.com
Wed Nov 7 18:24:22 EST 2012


Interesting.  There's intrinsic code in library_ call.cpp for this method.
It looks like that code may be missing some flavor of MemBarNode that kills
enregistering/hoisting of the interrupted field.  This should probably be
sent to the compiler folks.

Sent from my phone
On Nov 7, 2012 5:14 PM, "Dr Heinz M. Kabutz" <heinz at javaspecialists.eu>
wrote:

> 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 at cs.**oswego.edu <Concurrency-interest at cs.oswego.edu>
> http://cs.oswego.edu/mailman/**listinfo/concurrency-interest<http://cs.oswego.edu/mailman/listinfo/concurrency-interest>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20121107/6e512928/attachment-0001.html>


More information about the Concurrency-interest mailing list