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?
VMDisconnectedException
whatsoever, which made it even harder to figure out what the cause was. – ForeheadeventSet.resume()
because the suspends caused byinvokeMethod
are not recorded in the eventSet you're processing, they're 'extra'. And the way the JVM works, you can suspend a thread multiple times stacked on each other. It uses a counter for suspends and counts/subtracts the number of resumes, which need to be >= num of suspends for resume to really work! – ForeheadINVOKE_SINGLE_THREADED
, which is documented to hang as well. "The resumption of other threads during the invocation can be prevented by specifying the INVOKE_SINGLE_THREADED bit flag in the options argument; however, there is no protection against or recovery from the deadlocks described above, so this option should be used with great caution." – Forehead