[External] : Re: Thread.interrupted() is always false in debugger
Chris Plummer
chris.plummer at oracle.com
Wed Aug 21 22:00:19 UTC 2024
Actually it might be possible to view t.interrupted as true, but it
would need to be done so from another thread. I think you can have
Thread A sitting in a loop that doesn't do anything interruptible. Then
in Thread B you can interrupt Thread A and then have Thread B hit a
SUSPEND_ALL breakpoint. At that point if you viewed Thread A in the
debugger, the interrupted field should be set true.
Chris
On 8/21/24 12:59 PM, Chris Plummer wrote:
>
> 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/70490fff/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/70490fff/U29ugEUZ0HjcKutG-0001.png>
More information about the serviceability-dev
mailing list