[External] : Re: Thread.interrupted() is always false in debugger

Chris Plummer chris.plummer at oracle.com
Wed Aug 21 19:59:50 UTC 2024


In your video you are stepping through the following:


     public static boolean interrupted() {
         Thread t = currentThread();
         boolean interrupted = t.interrupted;
         // We may have been interrupted the moment after we read the field,
         // so only clear the field if we saw that it was set and will 
return
         // true; otherwise we could lose an interrupt.
         if (interrupted) {
             t.interrupted = false;
             clearInterruptEvent();
         }
         return interrupted;
     }


The debugger is showing t.interrupted as false, but when you step over 
the assignment to the interrupted local variable, it ends up assigning 
true and interrupted() returns true as a result. Yes, this seems very 
odd, but there is an explanation.


When you hit the breakpoint, there is an interrupt pending. As I 
mentioned earlier, the first RawMonitorWait that the debugger does on 
this thread will end up being interrupted as a result. The debug agent 
marks the thread as having been interrupted, and then does the wait 
again. So at this point t.interrupted will be false but 
ThreadNode->pendingInterrupt will be true. When the debug agent (and the 
debugger) are all done handling the event and the thread is resumed, the 
debug agent ends up in threadControl_onEventHandlerExit(), which checks 
the ThreadNode->pendingInterrupt flag and will reraise the interrupt if 
true. This means while the debugger is stopped at the event, the 
Thread's interrupted field is false, but once the Thread is resumed, it 
gets set true as a resulting of reraising the pending interrupt.


I think given how things work with the debug agent and interrupts, the 
debugger may never be able to observe t.interrupt set to true. Note that 
in your video walkthrough, even though it seems odd (and wrong) that 
t.interrupted is set false, the stepping you did worked properly. The 
thread is indeed marked as interrupted as it should be, and the 
interrupted() method returned true as it should. The only thing that is 
"wrong" is the misleading display of the t.interrupted field as false. 
Possibly this could be fixed by having the debug agent special case the 
access of that field and consult with ThreadNode->pendingInterrupt, but 
to me it doesn't seem important enough to do.


Chris



On 8/21/24 2:50 AM, Egor Ushakov wrote:
> Hi Chris,
>
> I tried it on jdk 23 and it works the same way :(
> It is clear that calling Thread.interrupted() in debugger should 
> modify the interrupted state, but it does not...
> It looks like the debugger is taking thread interrupted state from 
> somewhere else, and also somehow calling different methods...
> Check the attached video for more details.
>
> Thanks!
> Egor
>
> On 20.08.2024 18:27, Chris Plummer wrote:
>>
>> The presence of the breakpoint likely results in the debug agent 
>> executing code that does a JVMTI RawMonitorWait. However, there is 
>> code in place in the debug agent to repost the interrupt if it 
>> happens before or during the wait. See the code and comment in 
>> debugMonitorWait() and its call to handleInterrupt(), which calls 
>> threadControl_setPendingInterrupt(). It seems this code is failing 
>> somehow.
>>
>>
>> There were changes during JDK 23 in this area for virtual thread 
>> support, and the changes possibly could impact platform threads also. 
>> See JDK-8324868 <https://bugs.openjdk.org/browse/JDK-8324868> and 
>> JDK-8325187 <https://bugs.openjdk.org/browse/JDK-8325187>. It would 
>> be worth trying with the latest sources to see if the issue is still 
>> reproducible.
>>
>>
>> Regarding calling Thread.currentThread() from the watch panel, the 
>> use of the JDI method invocation support can change the state of the 
>> program being debugged. So if you do an invoke on the interrupted 
>> thread, it would not surprise me if the interrupt got cleared as a 
>> result, and I think this is to be expected.
>>
>>
>> Chris
>>
>>
>> On 8/20/24 6:47 AM, Gillespie, Oli wrote:
>>>
>>> There are lots of paths that clear the interrupted flag. In your 
>>> example, I hit at least this one when calling Thread.currentThread 
>>> from the watch panel:
>>>
>>> ```
>>>
>>>     at java.base/java.lang.Thread.interrupted(Thread.java:1030)
>>>     at java.base/jdk.internal.loader.Resource.getBytes(Resource.java:96)
>>>     at 
>>> java.base/jdk.internal.loader.URLClassPath$JarLoader$2.getBytes(URLClassPath.java:895)
>>>     at 
>>> java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:859)
>>>     at 
>>> java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:760)
>>>     at 
>>> java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:681)
>>>     at 
>>> java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:639)
>>>     at 
>>> java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
>>>     at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525)
>>>     at java.base/java.lang.Class.forName0(Native Method)
>>>     at java.base/java.lang.Class.forName(Class.java:467)
>>>
>>> ```
>>>
>>> but the key for your example seems to be 
>>> https://github.com/openjdk/jdk17u/blob/master/src/hotspot/share/prims/jvmtiRawMonitor.cpp 
>>> <https://urldefense.com/v3/__https://github.com/openjdk/jdk17u/blob/master/src/hotspot/share/prims/jvmtiRawMonitor.cpp__;!!ACWV5N9M2RV99hQ!LQga2NZfjZKMcpzfXgZa5xyH60muL5xAGlGJHOz7EkcDAjEAT82NT15T3VoPlIUvG59o4exJpW4y9uHOdnIc32D6i4ZQ$>. 
>>> If you replace is_interrupted(true) with is_interrupted(false) in 
>>> the 3 calls from that file, your example works as you expect. That 
>>> might help your investigations.
>>>
>>> Oli
>>> ------------------------------------------------------------------------
>>> *From:* serviceability-dev <serviceability-dev-retn at openjdk.org> on 
>>> behalf of Egor Ushakov <egor.ushakov at jetbrains.com>
>>> *Sent:* 20 August 2024 13:32:36
>>> *To:* serviceability-dev
>>> *Subject:* [EXTERNAL] Thread.interrupted() is always false in debugger
>>>
>>> *CAUTION*: This email originated from outside of the organization. 
>>> Do not click links or open attachments unless you can confirm the 
>>> sender and know the content is safe.
>>>
>>>
>>> Hi everyone!
>>>
>>> we have a long standing issue 
>>> https://youtrack.jetbrains.com/issue/IDEA-169706
>>> Maybe someone could clarify why it happens and if there's a possible 
>>> workaround.
>>> Here's the simplified test case:
>>> public class Interruption {
>>>      public static void main(String[]args) {
>>>          Thread thread =Thread.currentThread();
>>>          thread.interrupt();
>>>
>>>          if (Thread.interrupted()) { // <----- stop on a breakpoint here
>>>              System.out.println("Interrupted");
>>>          }else {
>>>              System.out.println("Not interrupted");
>>>          }
>>>      }
>>> }
>>>
>>> Obviously the program prints:
>>> Interrupted But if stopped on a breakpoint in the debugger, 
>>> evaluation of
>>> Thread.interrupted() always returns false.
>>> More of that/interrupted /field value in the thread object is also reported as false:
>>>
>>>
>>> If interrupted method is debugged step by step it is obvious that interrupted value is true,
>>> but the debugger continue to show it as false.
>>>
>>> Any ideas why it could happen and how to fix it?
>>>
>>> Thanks!
>>> Egor
>>>
>>>
>>>
>>> Amazon Development Centre (London) Ltd.Registered in England and 
>>> Wales with registration number 04543232 with its registered office 
>>> at 1 Principal Place, Worship Street, London EC2A 2FA, United Kingdom.
>>>
>>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/serviceability-dev/attachments/20240821/d461abe0/attachment-0001.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: U29ugEUZ0HjcKutG.png
Type: image/png
Size: 122053 bytes
Desc: not available
URL: <https://mail.openjdk.org/pipermail/serviceability-dev/attachments/20240821/d461abe0/U29ugEUZ0HjcKutG-0001.png>


More information about the serviceability-dev mailing list