I have my own JDI Debugger which calls the toString
method on some objects:
com.sun.jdi.ObjectReferenceobject object = ...
ThreadReference threadRef = frameProxy.threadProxy().getThreadReference();
Value value = object.invokeMethod(threadRef, toStringMethod,
Collections.EMPTY_LIST, ObjectReference.INVOKE_SINGLE_THREADED);
The problem is that even if no breakpoints are set inside the toString() method, the invokeMethod never terminates so my debugger hangs. For example this happens when I call this on a Double
object.
How can I kill the execution of invokeMethod
after some duration of time?
Update: I tried implementing my own Double
object and put some System.out.println()
statements at the start and end of the toString()
method and it seemed that the method is executed just fine but for some reason the debugger doesn't receive the result. Maybe this is a bug in JDI because there are many such bugs, but I am not looking for a solution for this, I am just looking for a way to abort the execution of invokeMethod()
if it takes too much time.
Update2: I tried what ThierryB was suggesting but I can only invoke frameProxy.threadProxy().stop(object);
in the manager thread. And the manager thread is blocked because of invokeMethod()
so it won't execute my command. I tried something like this:
boolean[] isFinished = new boolean[2];
isFinished[0] = false;
DebuggerManagerThreadImpl managerThread = debugProcess.getManagerThread();
new Thread(() - > {
try {
Thread.sleep(2000);
if (!isFinished[0]) {
System.out.println("Invoked");
managerThread.invokeCommand(new DebuggerCommand() {
@Override
public void action() {
try {
frameProxy.threadProxy().stop(object);
} catch (InvalidTypeException e) {
e.printStackTrace();
}
int threadStatus = frameProxy.threadProxy().status();
switch (threadStatus) {
case ThreadReference.THREAD_STATUS_RUNNING:
System.out.println("The thread is running.");
break;
case ThreadReference.THREAD_STATUS_ZOMBIE:
System.out.println("The thread has been completed.");
break;
case ThreadReference.THREAD_STATUS_WAIT:
System.out.println("The thread is waiting.");
break;
default:
System.out.println("The thread is not running / not waiting / not completed : but what is it doing right now ? (a little programmer joke ;) )");
}
}
@Override
public void commandCancelled() {
}
});
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
Value value = object.invokeMethod(threadRef, toStringMethod,
Collections.EMPTY_LIST, ObjectReference.INVOKE_SINGLE_THREADED);
isFinished[0] = true;
but frameProxy.threadProxy().stop(object);
is never executed because the DebuggerCommand's
action
method is not called(thread is blocked).
Also this is a Stack trace when my Debugger hangs and I forcefully stop the process:
com.sun.jdi.VMDisconnectedException
at com.jetbrains.jdi.TargetVM.waitForReply(TargetVM.java:317)
at com.jetbrains.jdi.VirtualMachineImpl.waitForTargetReply(VirtualMachineImpl.java:1170)
at com.jetbrains.jdi.PacketStream.waitForReply(PacketStream.java:86)
at com.jetbrains.jdi.JDWP$ObjectReference$InvokeMethod.waitForReply(JDWP.java:4840)
at com.jetbrains.jdi.ObjectReferenceImpl.invokeMethod(ObjectReferenceImpl.java:413)
UPDATE 3: which thread to use to invoke the Method? Currently I am using frameProxy.threadProxy().getThreadReference();
which works fine most of the time, but is it better to create a separate thread just for invoking methods on objects(along my JDI debugger I also have an instrumentation agent inside the application so I can create a separate thread just for this use case (maybe this will prevent deadlocks?)).
UPDATE 4: Currently I am using SUSPEND_ALL
as suspend policy, would it be better to use SUSPEND_EVENT_THREAD
instead?
You can use the interface ThreadReference
with the method void stop(ObjectReference throwable)
. The javadoc api tells "Stops this thread with an asynchronous exception.".
try {
com.sun.jdi.ObjectReferenceobject object = ...
ThreadReference threadRef = frameProxy.threadProxy().getThreadReference();
frameProxy.threadProxy().stop(object);
int threadStatus = frameProxy.threadProxy().status();
switch(threadStatus) {
case ThreadReference.THREAD_STATUS_RUNNING :
log.info("The thread is running.");
break;
case ThreadReference.THREAD_STATUS_ZOMBIE :
log.info("The thread has been completed.");
break;
case ThreadReference.THREAD_STATUS_WAIT :
log.info("The thread is waiting.");
break;
default :
log.info("The thread is not running / not waiting / not completed : but what is it doing right now ? (a little programmer joke ;) )");
}
} catch (ClassNotLoadedException cnle) {
// log exception, or display a message...
} catch (IncompatibleThreadStateException itse) {
// log exception, or display a message...
} catch (InvalidTypeException ite) {
// log exception, or display a message...
}
When you are checking your thread status with the status
method, you can find that values :
Hope you will find a way to do what you need to with the stuff I have provided here. Examples from here or the following suite test published on the website of Alvin Alexander could be helpfull too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With