JDK-8280971 : On windows, clhsdb thread IDs are not always the same across attaches
  • Type: Bug
  • Component: hotspot
  • Sub-Component: svc-agent
  • Affected Version: 18,19
  • Priority: P5
  • Status: New
  • Resolution: Unresolved
  • Submitted: 2022-01-31
  • Updated: 2022-01-31
Related Reports
Relates :  
Description
If you execute the clhsdb "threads" or "threadcontext -a" commands, they will dump the "thread id" of each thread, which just shows up in the output as "id=<id>". This <id> can be used in a number of other clhsdb commands, such as dumpreplaydata, where, thread, and threadcontext (of a single thread).

On Windows, the <id> for a thread might change across attaches. So that means an <id> captured during a "threads" command may not work as expected if you detach and the re-attach. This is the root cause of the JDK-8280770 failures. The test was executing "threadcontext -a", gleaned the <id> of the SteadyStateThread from the the output, and then used it in the "threadcontext <id>" command. The problem is the test also detaches after the first threadcontext command and re-attaches for the 2nd, and the <id> for SteadyStateThread changed during this time.

The reason this happens on windows is because it chooses to convert from the "sysId" (what windows calls to "system thread ID") to what windows refers to as the "engine Thread ID". SA on windows has chosen to use the "engine Thread ID" as the thread ID rather than the "system thread ID". A bit of info on each can be found here:

https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/controlling-threads-and-processes

It appears that the "engine thread ID" is not necessarily consistent across attaches. It's not clear that the "system thread ID" is either. More investigating is needed to determine that.

SA gets the thread ID in a somewhat round about way.

    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    thread.printThreadIDOn(new PrintStream(bos));
    String threadID = bos.toString();

The printThreadIDOn call boils down to the following:

For LinuxThread.java:

    public String toString() {
        return Integer.toString(lwp_id);
    }

For BSD:

    public String toString() {
        return Integer.toString(thread_id);
    }

For Windows:

  public String toString() {
    return Long.toString(getThreadID());
  }

  /** Retrieves the thread ID of this thread by examining the Thread
      Information Block. */
  private long getThreadID() {
    if (!gotID) {
       id = debugger.getThreadIdFromSysId(sysId);
       gotID = true;
    }

    return id;
  }

On Windows the getThreadIdFromSysId() call is what returns the "engine thread ID". It's unclear why SA initially stores the "system thread ID" for each thread, but rather than use it as the thread ID it chooses to convert it to the "engine thread ID". It might be because this is the ID that other thread related APIs require. If so this issue could be fixed by using the "system thread ID" as the SA thread ID, and only convert to the "engine thread ID" when using APIs that require it.