Как прервать длительный вызов invokeMethod на com.sun.jdi.ObjectReference?

У меня есть собственный отладчик JDI, который вызывает метод toString для некоторых объектов:

com.sun.jdi.ObjectReferenceobject object = ...
ThreadReference threadRef = frameProxy.threadProxy().getThreadReference();
Value value = object.invokeMethod(threadRef, toStringMethod,
                    Collections.EMPTY_LIST, ObjectReference.INVOKE_SINGLE_THREADED);

Проблема в том, что даже если внутри метода toString() не установлены точки останова, метод invokeMethod никогда не завершается, поэтому мой отладчик зависает. Например, это происходит, когда я вызываю это для объекта Double.

Как я могу остановить выполнение invokeMethod через некоторое время?

Обновление: я попытался реализовать свой собственный объект Double и поместил несколько операторов System.out.println() в начало и конец метода toString(), и мне показалось, что метод выполняется нормально, но по какой-то причине отладчик не получает результат. Возможно, это ошибка в JDI, потому что таких ошибок много, но я не ищу решение для этого, я просто ищу способ прервать выполнение invokeMethod(), если это займет слишком много времени. время.

Update2: я попробовал то, что предлагал ThierryB, но я могу вызвать только frameProxy.threadProxy().stop(object); в потоке менеджера. И поток менеджера заблокирован из-за invokeMethod(), поэтому он не выполнит мою команду. Я пробовал что-то вроде этого:

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;

но frameProxy.threadProxy().stop(object); никогда не выполняется, потому что метод DebuggerCommand's action не вызывается (поток заблокирован).

Также это трассировка стека, когда мой отладчик зависает, и я принудительно останавливаю процесс:

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)

ОБНОВЛЕНИЕ 3: какой поток использовать для вызова метода? В настоящее время я использую frameProxy.threadProxy().getThreadReference();, который отлично работает большую часть времени, но лучше ли создать отдельный поток только для вызова методов на объектах (наряду с моим отладчиком JDI у меня также есть инструментальный агент внутри приложения, поэтому я могу создать отдельный поток только для этого варианта использования (может быть, это предотвратит взаимоблокировки?)).

ОБНОВЛЕНИЕ 4: В настоящее время я использую SUSPEND_ALL в качестве политики приостановки, не лучше ли вместо этого использовать SUSPEND_EVENT_THREAD?


person Nfff3    schedule 17.08.2020    source источник
comment
Обязательно внимательно прочитайте параграф описания javadoc для invokeMethod [ docs.oracle.com/javase/8/docs/ jdk/api/jpda/jdi/com/sun/jdi/ ] подробно описывает множество условий, при которых целевая виртуальная машина может столкнуться с взаимоблокировкой.   -  person simonarame    schedule 20.08.2020


Ответы (1)


Вы можете использовать интерфейс ThreadReference с методом void stop(ObjectReference throwable). API-интерфейс javadoc сообщает, что этот поток останавливается с асинхронным исключением.

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...
}

Когда вы проверяете статус своего потока с помощью метода status, вы можете найти следующие значения:

  • THREAD_STATUS_UNKNOWN
  • THREAD_STATUS_ZOMBIE
  • THREAD_STATUS_RUNNING
  • THREAD_STATUS_SLEEPING
  • THREAD_STATUS_MONITOR
  • THREAD_STATUS_WAIT
  • THREAD_STATUS_NOT_STARTED

Надеюсь, вы найдете способ сделать то, что вам нужно, с материалом, который я предоставил здесь. Примеры из здесь или следующий набор тестов, опубликованный на веб-сайте Элвина Александра, также может быть полезен.

person BendaThierry.com    schedule 19.08.2020
comment
Спасибо. Не могли бы вы взглянуть на мое второе обновление. Я уверен, что я что-то упускаю. - person Nfff3; 20.08.2020