JDK-4783403 : JDI ThreadReference.frameCount() fails when thread is sleeping
  • Type: Bug
  • Component: core-svc
  • Sub-Component: debugger
  • Affected Version: 1.4.0,1.4.1,1.4.2
  • Priority: P4
  • Status: Closed
  • Resolution: Won't Fix
  • OS: generic,linux_redhat_6.1,windows_xp
  • CPU: generic,x86
  • Submitted: 2002-11-22
  • Updated: 2023-12-14
  • Resolved: 2016-11-03
Description
See regressionTestsInWaiting/SleepFrameCountTest.java

Name: tb29552			Date: 11/22/2002

FULL PRODUCT VERSION :
java version "1.4.1_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_01-b01)
Java HotSpot(TM) Client VM (build 1.4.1_01-b01, mixed mode)

FULL OPERATING SYSTEM VERSION :
Microsoft Windows XP [Version 5.1.2600]

ADDITIONAL OPERATING SYSTEMS :
Linux (Redhat 7.2)



A DESCRIPTION OF THE PROBLEM :
Starting with JDK 1.4.1, my debugger can no longer
interrogate the call stack of a thread blocked in a call to
Thread.sleep().  It receives
IncompatibleThreadStateExceptions, even when the thread is
suspended.  It receives this exception when calling
ThreadReference.frameCount() or ThreadReference.frames().

Two programs are attached to demonstrate the problem.  The
first is a simple program that just issues a sleep().  The
second uses the JDI API to attach to the test program and
type the number of frames in the call stack of the "main"
thread.  When this program attaches to the test program, the
failure is demonstrated.

The program works fine if the test program is blocked in a
call to wait() instead of Thread.sleep().


REGRESSION.  Last worked in version 1.4

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Run the first program (Sleeper) with the following options:
   java -Xdebug
-Xrunjdwp:transport=dt_socket,server=y,address=8000,suspend=n
Sleeper

2. Run the second program (JDIStackBug) with tools.jar in the
   class path, on the same machine as the test program.

3. Observe IncompatibleThreadState exception, even though
thread is suspended.

EXPECTED VERSUS ACTUAL BEHAVIOR :
Expect program that uses JDI to output the depth of the call
stack.  Instead, it encounters and exception.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
com.sun.jdi.IncompatibleThreadStateException
 at com.sun.tools.jdi.ThreadReferenceImpl.frameCount(ThreadReferenceImpl.java:263)
 at JDIStackBug.test(JDIStackBug.java:70)
 at JDIStackBug.main(JDIStackBug.java:12)


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
Sleeper.java:

class Sleeper {
   public static void main(String[] args) {
      new Sleeper().test();
   }

   void test() {
      try {
         Thread.sleep(500000);
      } catch (InterruptedException e) {}
   }
}

JDIStackBug.java:

import java.util.*;
import java.io.*;
import com.sun.jdi.*;
import com.sun.jdi.connect.*;
import com.sun.jdi.request.*;
import com.sun.jdi.event.*;

public class JDIStackBug {
   VirtualMachine vm;

   public static void main(String[] args) {
      new JDIStackBug().test(args);
   }

   void test(String[] args) {
      VirtualMachineManager vmManager = Bootstrap.virtualMachineManager();
      List connectors = vmManager.attachingConnectors();
      Iterator iterator = connectors.iterator();
      AttachingConnector connector = null;
      while (iterator.hasNext()) {
         AttachingConnector candidate = (AttachingConnector) iterator.next();
         if (candidate.name().equals("com.sun.jdi.SocketAttach"))
            connector = candidate;
      }

      if (connector == null) {
         System.err.println("Can't find connector \"com.sun.jdi.SocketAttach\"");
         return;
      }

      // Set startup options
      Map connectorArgs = connector.defaultArguments();
      Connector.Argument argInfo = (Connector.Argument)
connectorArgs.get("hostname");
      argInfo.setValue("localhost");
      argInfo = (Connector.Argument) connectorArgs.get("port");
      argInfo.setValue("8000");

      try {
         vm = connector.attach(connectorArgs);
      } catch (IllegalConnectorArgumentsException e) {
         System.err.println("Exception attaching to JVM:");
         e.printStackTrace();
      } catch (IOException e) {
         System.err.println("I/O Exception attaching to JVM:");
         e.printStackTrace();
      }

      System.out.println("Virtual machine attached.");

      Thread eventThread = new Thread(new Runnable() {
         public void run() {
            readEvents();
         }
      }, "Event reading thread");
      eventThread.start();

      try {
         System.out.println("Suspending VM...");
         vm.suspend();

         List allThreads = vm.allThreads();
         iterator = allThreads.iterator();
         while (iterator.hasNext()) {
            ThreadReference thread = (ThreadReference) iterator.next();
            if (thread.name().equals("main")) {
               vm.setDebugTraceMode(VirtualMachine.TRACE_ALL);
               System.out.println("Thread \"main\"");
               System.out.println(" suspended == "+thread.isSuspended());
               // The following ThreadReference.frameCount() call fails
               System.out.println(" stack frame count == "+thread.frameCount());
               vm.setDebugTraceMode(VirtualMachine.TRACE_NONE);
            }
         }

      } catch (Exception e) {
         e.printStackTrace();
      }

      System.out.println("Resuming JVM...");
      vm.resume();
      System.out.println("Detaching from VM...");
      vm.dispose();
   }

   void readEvents() {
      EventQueue eventQueue = vm.eventQueue();
      boolean connected = true;

      while (connected) {
         try {
            EventSet eventSet = eventQueue.remove();
            EventIterator iterator = eventSet.eventIterator();
            while (iterator.hasNext()) {
               Event event = iterator.nextEvent();

               if (event instanceof VMDisconnectEvent)
                  connected = false;
            }

            eventSet.resume();

         } catch (InterruptedException e) {
            System.err.println("Thread reading JVM event queue was interrupted!");
         } catch (VMDisconnectedException e) {
            System.out.println("Received a VMDisconnectedException");
            connected = false;
         }
      }
   }
}
---------- END SOURCE ----------

CUSTOMER WORKAROUND :
I haven't found a workaround.
(Review ID: 167072) 
======================================================================

Comments
This is not on our list of current priorities, if this changes please re-open this issue.
03-11-2016

PUBLIC COMMENTS .
10-06-2004