JDI ThreadReference.frame() wirft IncompatibleThreadStateException


yss

Grünschnabel
#1
Guten Morgen

Nach langer Suche im Internet bin ich endlich auf eine brauchbare Einführung zum JDI hier auf tutorials.de gestoßen. Mein Ziel ist es ebenfalls, Zeile für Zeile durch ein Java Programm durchzusteppen und Informationen zu meinen Objekten auszulesen.
Nun hab ich mal den Code von Thomas fast 1zu1 adaptiert und ein bisschen rumgespielt. Dabei ist mir aufgefallen, dass durch Entfernen des Thread.sleep() Statements eine IncompatibleThreadStateException geworfen wir beim Aufruf von

Code:
stackFrame = mainThread.frame(0);
Theoretisch müsste ich im Programmablauf auch warten, bis die aktuelle Anweisung in der Remote VM ausgeführt wurde und dann erst eine Zeile weiter gehen. Weiß da zufällig jemand mehr, warum ich diese Exception bekomme und wie ich dieses Problem lösen kann?

Hier mein Code:

Code:
public class VMStart {

public static void main(String[] args) {

    //Check for argument count
    if(args.length != 3){
        System.err.println("Not enough parameter!");
        System.exit(0);
    }

    String cwd = "", mainClass = "", vmPort = "";

    cwd = args[0];
    mainClass = args[1];
    vmPort = args[2];

    System.out.println("CWD: " + cwd);
    System.out.println("MainClass: " + mainClass);
    System.out.println("VM Port: " + vmPort);

    //Init vm arguments and settings
    VirtualMachineManager vmm = Bootstrap.virtualMachineManager();
    AttachingConnector ac = vmm.attachingConnectors().get(0);

    //Setting port
    Map<String, Connector.Argument> env = ac.defaultArguments();
    Connector.Argument port = env.get("port");
    port.setValue(vmPort);

    //Setting hostname
    Connector.Argument hostname = env.get("hostname");
    hostname.setValue("localhost");

    //Attach vm to remote vm
    VirtualMachine vm = null;
    try {
        vm = ac.attach(env);
    } catch (IOException | IllegalConnectorArgumentsException e) {
        //Doesn't work, stop here...
        System.err.println("Can't connect to vm!");
        e.printStackTrace();
        System.exit(0);
    }

    //Create EventQueue and EventRequestManager for further event handling
    EventQueue eventQueue = vm.eventQueue();
    EventRequestManager mgr = vm.eventRequestManager();

    //Set the vm to sleep for further operations
    vm.suspend();

    //Searching for our main thread reference
    ThreadReference mainThread = null;
    List<ThreadReference> threads = vm.allThreads();
    for (ThreadReference thread : threads) {
        if ("main".equals(thread.name())) {
            mainThread = thread;
        }
    }

    //Create and register MethodEntryRequest, so we can pause execution at first line of main later on
    MethodEntryRequest methodEntryRequest = mgr.createMethodEntryRequest();
    methodEntryRequest.addClassFilter(mainClass);
    methodEntryRequest.addThreadFilter(mainThread);
    methodEntryRequest.enable();

    //Resume the execution of the remote vm
    vm.resume();

    //Resume the execution of the main thread in remote vm
    mainThread.resume();

    //Waiting for our needed MethodEntryEvent so execution started at first line of main method
    Event event = null;
    while (true) {
        EventSet eventSet = null;
        try {
            eventSet = eventQueue.remove();
        } catch (InterruptedException e) {
            System.err.println("Something went wrong while waiting for MethodEntryEvent");
            e.printStackTrace();
            System.exit(0);
        }
        event = eventSet.eventIterator().next();
        if (event instanceof MethodEntryEvent) {
            break;
        }
    }

    //Indicates whether there is still code execution in our remote vm
    boolean codeIsExecuting = true;

    //Step loop until there is no code execution
    while(codeIsExecuting){
        //Filter for steeping not into java api methods
        final String[] noBreakpointRequests = {"java.*", "javax.*", "sun.*", "com.sun.*"};

        //Creating our StepRequest for each line of code
        StepRequest stepRequest = mgr.createStepRequest(mainThread, StepRequest.STEP_LINE, StepRequest.STEP_INTO);
        for(String classInFilter : noBreakpointRequests){ //Apply filter
            stepRequest.addClassExclusionFilter(classInFilter);
        }
        stepRequest.addCountFilter(1);
        try{
            stepRequest.enable();
        }catch(IllegalThreadStateException e){
            //program reached end of code, so there is no code execution anymore
            codeIsExecuting = false;
            System.out.println("Code execution ended...");
            break;
        }

        //Extract data from current vm execution state
        //TODO
        System.out.println("TODO - extract data from current vm execution state");

        //Test
        StackFrame stackFrame = null;
        try {
            stackFrame = mainThread.frame(0);
            System.out.println(stackFrame.location());
        } catch (IncompatibleThreadStateException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        //Resume vm for code execution
        vm.resume();

        try {
            Thread.sleep(10L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //StepRequest is done, remove it from event queue to prevent lock
        mgr.deleteEventRequest(stepRequest);
    }

    //Debugging has ended, we free our remote vm
    try{
        vm.dispose();
    }catch(VMDisconnectedException e){

    }

    //Print results
    //TODO
    System.out.println("TODO - print results...");

}
}