[10] RFR 8181647: jhsdb jstack could not output thread name

Yasumasa Suenaga yasuenag at gmail.com
Tue Jul 4 22:43:54 UTC 2017


Hi Chihiro,

It looks good to me.
However, I cannot be a sponsor because I cannot access JPRT. The change(s) for HotSpot should be pushed via JPRT.

Please find a sponsor for this change.
(Of course, you can list me as a reviewer (ysuenaga))


Thanks,

Yasumasa


On 2017/07/05 2:17, chihiro ito wrote:
> Hi Yasumasa,
>
> Thank you for reviewing.
>
> I modified these following source code that you commented.
>> + out.print(String.format("0x%016x",this.getAddress().asLongValue()));
>> +    out.print(" nid=");
>> +    out.print(String.format("0x%x ",this.getOSThread().threadId()));
>> +    out.print(getOSThread().getThreadState().getPrintVal());
>> +    out.print(" [");
>> +    if( this.getLastJavaSP() == null){
>> +      out.print(String.format("0x%016x",0L));
>
> Based on your advice, I have modified as following. Could you possibly review for this code ?
>
> +  private static final String  ADDRESS_FORMAT = VM.getVM().isLP64() ? "0x%016x" : "0x%08x";
>
> +    out.print(this.getAddress());
> +    out.print(" nid=");
> +    out.print(String.format("0x%x ",this.getOSThread().threadId()));
> +    out.print(getOSThread().getThreadState().getPrintVal());
> +    out.print(" [");
> +    if( this.getLastJavaSP() == null){
> +      out.print(String.format(ADDRESS_FORMAT,0L));
>
> Regards,
> Chihiro
>
>
> hg diff -g is following.
>
> diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/OopUtilities.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/OopUtilities.java
> --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/OopUtilities.java
> +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/OopUtilities.java
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
>   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>   *
>   * This code is free software; you can redistribute it and/or modify it
> @@ -59,20 +59,20 @@
>    // parkBlocker field is new since 1.6
>    private static OopField threadParkBlockerField;
>
> +  private static IntField threadPriorityField;
> +  private static BooleanField threadDaemonField;
> +
>    // possible values of java_lang_Thread::ThreadStatus
>    private static int THREAD_STATUS_NEW;
> -  /*
> -    Other enum constants are not needed as of now. Uncomment these as and when needed.
>
> -    private static int THREAD_STATUS_RUNNABLE;
> -    private static int THREAD_STATUS_SLEEPING;
> -    private static int THREAD_STATUS_IN_OBJECT_WAIT;
> -    private static int THREAD_STATUS_IN_OBJECT_WAIT_TIMED;
> -    private static int THREAD_STATUS_PARKED;
> -    private static int THREAD_STATUS_PARKED_TIMED;
> -    private static int THREAD_STATUS_BLOCKED_ON_MONITOR_ENTER;
> -    private static int THREAD_STATUS_TERMINATED;
> -  */
> +  private static int THREAD_STATUS_RUNNABLE;
> +  private static int THREAD_STATUS_SLEEPING;
> +  private static int THREAD_STATUS_IN_OBJECT_WAIT;
> +  private static int THREAD_STATUS_IN_OBJECT_WAIT_TIMED;
> +  private static int THREAD_STATUS_PARKED;
> +  private static int THREAD_STATUS_PARKED_TIMED;
> +  private static int THREAD_STATUS_BLOCKED_ON_MONITOR_ENTER;
> +  private static int THREAD_STATUS_TERMINATED;
>
>    // java.util.concurrent.locks.AbstractOwnableSynchronizer fields
>    private static OopField absOwnSyncOwnerThreadField;
> @@ -229,20 +229,19 @@
>        threadStatusField = (IntField) k.findField("threadStatus", "I");
>        threadParkBlockerField = (OopField) k.findField("parkBlocker",
>                                       "Ljava/lang/Object;");
> +      threadPriorityField = (IntField) k.findField("priority", "I");
> +      threadDaemonField = (BooleanField) k.findField("daemon", "Z");
>        TypeDataBase db = VM.getVM().getTypeDataBase();
>        THREAD_STATUS_NEW = db.lookupIntConstant("java_lang_Thread::NEW").intValue();
> -      /*
> -        Other enum constants are not needed as of now. Uncomment these as and when needed.
>
> -        THREAD_STATUS_RUNNABLE = db.lookupIntConstant("java_lang_Thread::RUNNABLE").intValue();
> -        THREAD_STATUS_SLEEPING = db.lookupIntConstant("java_lang_Thread::SLEEPING").intValue();
> -        THREAD_STATUS_IN_OBJECT_WAIT = db.lookupIntConstant("java_lang_Thread::IN_OBJECT_WAIT").intValue();
> -        THREAD_STATUS_IN_OBJECT_WAIT_TIMED = db.lookupIntConstant("java_lang_Thread::IN_OBJECT_WAIT_TIMED").intValue();
> -        THREAD_STATUS_PARKED = db.lookupIntConstant("java_lang_Thread::PARKED").intValue();
> -        THREAD_STATUS_PARKED_TIMED = db.lookupIntConstant("java_lang_Thread::PARKED_TIMED").intValue();
> -        THREAD_STATUS_BLOCKED_ON_MONITOR_ENTER = db.lookupIntConstant("java_lang_Thread::BLOCKED_ON_MONITOR_ENTER").intValue();
> -        THREAD_STATUS_TERMINATED = db.lookupIntConstant("java_lang_Thread::TERMINATED").intValue();
> -      */
> +      THREAD_STATUS_RUNNABLE = db.lookupIntConstant("java_lang_Thread::RUNNABLE").intValue();
> +      THREAD_STATUS_SLEEPING = db.lookupIntConstant("java_lang_Thread::SLEEPING").intValue();
> +      THREAD_STATUS_IN_OBJECT_WAIT = db.lookupIntConstant("java_lang_Thread::IN_OBJECT_WAIT").intValue();
> +      THREAD_STATUS_IN_OBJECT_WAIT_TIMED = db.lookupIntConstant("java_lang_Thread::IN_OBJECT_WAIT_TIMED").intValue();
> +      THREAD_STATUS_PARKED = db.lookupIntConstant("java_lang_Thread::PARKED").intValue();
> +      THREAD_STATUS_PARKED_TIMED = db.lookupIntConstant("java_lang_Thread::PARKED_TIMED").intValue();
> +      THREAD_STATUS_BLOCKED_ON_MONITOR_ENTER = db.lookupIntConstant("java_lang_Thread::BLOCKED_ON_MONITOR_ENTER").intValue();
> +      THREAD_STATUS_TERMINATED = db.lookupIntConstant("java_lang_Thread::TERMINATED").intValue();
>
>        if (Assert.ASSERTS_ENABLED) {
>          // it is okay to miss threadStatusField, because this was
> @@ -331,4 +330,46 @@
>        return absOwnSyncOwnerThreadField.getValue(oop);
>      }
>    }
> +
> +  public static int threadOopGetPriority(Oop threadOop) {
> +    initThreadFields();
> +    if (threadPriorityField != null) {
> +      return threadPriorityField.getValue(threadOop);
> +    } else {
> +      return 0;
> +    }
> +  }
> +
> +  public static boolean threadOopGetDaemon(Oop threadOop) {
> +    initThreadFields();
> +    if (threadDaemonField != null) {
> +      return threadDaemonField.getValue(threadOop);
> +    } else {
> +      return false;
> +    }
> +  }
> +
> +  public static String threadOopGetThreadStatusName(Oop threadOop) {
> +    int status = OopUtilities.threadOopGetThreadStatus(threadOop);
> +    if( status == THREAD_STATUS_NEW ){
> +      return "NEW";
> +    }else if(status == THREAD_STATUS_RUNNABLE ){
> +      return "RUNNABLE";
> +    }else if(status == THREAD_STATUS_SLEEPING ){
> +      return "TIMED_WAITING (sleeping)";
> +    }else if(status == THREAD_STATUS_IN_OBJECT_WAIT ){
> +      return "WAITING (on object monitor)";
> +    }else if(status == THREAD_STATUS_IN_OBJECT_WAIT_TIMED ){
> +      return "TIMED_WAITING (on object monitor)";
> +    }else if(status == THREAD_STATUS_PARKED ){
> +      return "WAITING (parking)";
> +    }else if(status == THREAD_STATUS_PARKED_TIMED ){
> +      return "TIMED_WAITING (parking)";
> +    }else if(status == THREAD_STATUS_BLOCKED_ON_MONITOR_ENTER ){
> +      return "BLOCKED (on object monitor)";
> +    }else if(status == THREAD_STATUS_TERMINATED ){
> +      return "TERMINATED";
> +    }
> +    return "UNKNOWN";
> +  }
>  }
> diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java
> --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java
> +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java
> @@ -70,6 +70,8 @@
>    private static int           NOT_TERMINATED;
>    private static int           EXITING;
>
> +  private static final String  ADDRESS_FORMAT = VM.getVM().isLP64() ? "0x%016x" : "0x%08x";
> +
>    static {
>      VM.registerVMInitializedObserver(new Observer() {
>          public void update(Observable o, Object data) {
> @@ -475,4 +477,35 @@
>      return access.getLastSP(addr);
>    }
>
> +
> +  public void printThreadInfoOn(PrintStream out){
> +
> +    Oop threadOop = this.getThreadObj();
> +
> +    out.print("\"");
> +    out.print(this.getThreadName());
> +    out.print("\" #");
> +    out.print(OopUtilities.threadOopGetTID(threadOop));
> +    if( OopUtilities.threadOopGetDaemon(threadOop) ){
> +      out.print(" daemon");
> +    }
> +    out.print(" prio=");
> +    out.print(OopUtilities.threadOopGetPriority(threadOop));
> +    out.print(" tid=");
> +    out.print(this.getAddress());
> +    out.print(" nid=");
> +    out.print(String.format("0x%x ",this.getOSThread().threadId()));
> +    out.print(getOSThread().getThreadState().getPrintVal());
> +    out.print(" [");
> +    if( this.getLastJavaSP() == null){
> +      out.print(String.format(ADDRESS_FORMAT,0L));
> +    } else {
> +      out.print(this.getLastJavaSP().andWithMask(~0xFFF));
> +    }
> +    out.println("]");
> +    out.print("   java.lang.Thread.State: ");
> + out.println(OopUtilities.threadOopGetThreadStatusName(threadOop));
> +    out.print("   JavaThread state: _thread_");
> +    out.println(this.getThreadState().toString().toLowerCase());
> +  }
>  }
> diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/OSThread.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/OSThread.java
> --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/OSThread.java
> +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/OSThread.java
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved.
>   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>   *
>   * This code is free software; you can redistribute it and/or modify it
> @@ -33,6 +33,19 @@
>  public class OSThread extends VMObject {
>      private static JIntField interruptedField;
>      private static Field threadIdField;
> +    private static CIntegerField threadStateField;
> +
> +    // ThreadStates read from underlying process
> +    private static int ALLOCATED;
> +    private static int INITIALIZED;
> +    private static int RUNNABLE;
> +    private static int MONITOR_WAIT;
> +    private static int CONDVAR_WAIT;
> +    private static int OBJECT_WAIT;
> +    private static int BREAKPOINTED;
> +    private static int SLEEPING;
> +    private static int ZOMBIE;
> +
>      static {
>          VM.registerVMInitializedObserver(new Observer() {
>              public void update(Observable o, Object data) {
> @@ -45,6 +58,17 @@
>          Type type = db.lookupType("OSThread");
>          interruptedField = type.getJIntField("_interrupted");
>          threadIdField = type.getField("_thread_id");
> +        threadStateField = type.getCIntegerField("_state");
> +
> +        ALLOCATED = db.lookupIntConstant("ALLOCATED").intValue();
> +        INITIALIZED = db.lookupIntConstant("INITIALIZED").intValue();
> +        RUNNABLE = db.lookupIntConstant("RUNNABLE").intValue();
> +        MONITOR_WAIT = db.lookupIntConstant("MONITOR_WAIT").intValue();
> +        CONDVAR_WAIT = db.lookupIntConstant("CONDVAR_WAIT").intValue();
> +        OBJECT_WAIT = db.lookupIntConstant("OBJECT_WAIT").intValue();
> +        BREAKPOINTED = db.lookupIntConstant("BREAKPOINTED").intValue();
> +        SLEEPING = db.lookupIntConstant("SLEEPING").intValue();
> +        ZOMBIE = db.lookupIntConstant("ZOMBIE").intValue();
>      }
>
>      public OSThread(Address addr) {
> @@ -59,4 +83,28 @@
>          return threadIdField.getJInt(addr);
>      }
>
> +    public ThreadState getThreadState() {
> +        int val = (int)threadStateField.getValue(addr);
> +        if (val ==  ALLOCATED) {
> +            return ThreadState.ALLOCATED;
> +        } else if (val ==  INITIALIZED) {
> +            return ThreadState.INITIALIZED;
> +        } else if (val ==  RUNNABLE) {
> +            return ThreadState.RUNNABLE;
> +        } else if (val ==  MONITOR_WAIT) {
> +            return ThreadState.MONITOR_WAIT;
> +        } else if (val ==  CONDVAR_WAIT) {
> +            return ThreadState.CONDVAR_WAIT;
> +        } else if (val ==  OBJECT_WAIT) {
> +            return ThreadState.OBJECT_WAIT;
> +        } else if (val ==  BREAKPOINTED) {
> +            return ThreadState.BREAKPOINTED;
> +        } else if (val ==  SLEEPING) {
> +            return ThreadState.SLEEPING;
> +        } else if (val ==  ZOMBIE) {
> +            return ThreadState.ZOMBIE;
> +        } else {
> +            throw new RuntimeException("Illegal thread state " + val);
> +        }
> +    }
>  }
> diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadState.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadState.java
> new file mode 100644
> --- /dev/null
> +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadState.java
> @@ -0,0 +1,60 @@
> +/*
> + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
> + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
> + *
> + * This code is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 only, as
> + * published by the Free Software Foundation.
> + *
> + * This code is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> + * version 2 for more details (a copy is included in the LICENSE file that
> + * accompanied this code).
> + *
> + * You should have received a copy of the GNU General Public License version
> + * 2 along with this work; if not, write to the Free Software Foundation,
> + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
> + * or visit www.oracle.com if you need additional information or have any
> + * questions.
> + */
> +
> +package sun.jvm.hotspot.runtime;
> +
> +/** This is a type-safe enum mirroring the ThreadState enum in
> + osThread.hpp. The conversion between the underlying ints
> + and these values is done in OSThread. */
> +
> +public class ThreadState {
> +
> +    private String printVal;
> +
> +    /** Memory has been allocated but not initialized */
> +    public static final ThreadState ALLOCATED = new ThreadState("allocated");
> +    /** The thread has been initialized but yet started */
> +    public static final ThreadState INITIALIZED = new ThreadState("initialized");
> +    /** Has been started and is runnable, but not necessarily running */
> +    public static final ThreadState RUNNABLE = new ThreadState("runnable");
> +    /** Waiting on a contended monitor lock */
> +    public static final ThreadState MONITOR_WAIT = new ThreadState("waiting for monitor entry");
> +    /** Waiting on a condition variable */
> +    public static final ThreadState CONDVAR_WAIT = new ThreadState("waiting on condition");
> +    /** Waiting on an Object.wait() call */
> +    public static final ThreadState OBJECT_WAIT = new ThreadState("in Object.wait()");
> +    /** Suspended at breakpoint */
> +    public static final ThreadState BREAKPOINTED = new ThreadState("at breakpoint");
> +    /** Thread.sleep() */
> +    public static final ThreadState SLEEPING = new ThreadState("sleeping");
> +    /** All done, but not reclaimed yet */
> +    public static final ThreadState ZOMBIE = new ThreadState("zombie");
> +
> +    private ThreadState(String printVal){
> +        this.printVal = printVal;
> +    }
> +
> +    public String getPrintVal() {
> +        return printVal;
> +    }
> +}
> diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java
> --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java
> +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
>   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>   *
>   * This code is free software; you can redistribute it and/or modify it
> @@ -88,6 +88,10 @@
>                 out.print("----------------- ");
>                 out.print(th);
>                 out.println(" -----------------");
> +               JavaThread jthread = (JavaThread) proxyToThread.get(th);
> +               if (jthread != null) {
> +                  jthread.printThreadInfoOn(out);
> +               }
>                 while (f != null) {
>                    ClosestSymbol sym = f.closestSymbolToPC();
>                    Address pc = f.pc();
> diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java
> --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java
> +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
>   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>   *
>   * This code is free software; you can redistribute it and/or modify it
> @@ -74,14 +74,7 @@
>              int i = 1;
>              for (JavaThread cur = threads.first(); cur != null; cur = cur.next(), i++) {
>                  if (cur.isJavaThread()) {
> -                    Address sp = cur.getLastJavaSP();
> -                    tty.print("Thread ");
> -                    cur.printThreadIDOn(tty);
> -                    tty.print(": (state = " + cur.getThreadState());
> -                    if (verbose) {
> -                        tty.println(", current Java SP = " + sp);
> -                    }
> -                    tty.println(')');
> +                    cur.printThreadInfoOn(tty);
>                      try {
>                          for (JavaVFrame vf = cur.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) {
>                              Method method = vf.getMethod();
> diff --git a/src/share/vm/runtime/vmStructs.cpp b/src/share/vm/runtime/vmStructs.cpp
> --- a/src/share/vm/runtime/vmStructs.cpp
> +++ b/src/share/vm/runtime/vmStructs.cpp
> @@ -981,6 +981,7 @@
> /************/ \
> \
>    volatile_nonstatic_field(OSThread, _interrupted, jint)                                  \
> +  volatile_nonstatic_field(OSThread, _state, ThreadState) \
> \
> /************************/ \
>    /* OopMap and OopMapSet */ \
> @@ -2186,6 +2187,7 @@
> declare_integer_type(Generation::Name) \
> declare_integer_type(InstanceKlass::ClassState) \
> declare_integer_type(JavaThreadState) \
> + declare_integer_type(ThreadState) \
> declare_integer_type(Location::Type) \
> declare_integer_type(Location::Where) \
> declare_integer_type(Flag::Flags) \
> @@ -2443,6 +2445,20 @@
> declare_constant(JavaThread::_not_terminated) \
> declare_constant(JavaThread::_thread_exiting) \
> \
> + /*******************/ \
> +  /* JavaThreadState */                                                   \
> + /*******************/ \
> + \
> + declare_constant(ALLOCATED) \
> + declare_constant(INITIALIZED) \
> + declare_constant(RUNNABLE) \
> + declare_constant(MONITOR_WAIT) \
> + declare_constant(CONDVAR_WAIT) \
> + declare_constant(OBJECT_WAIT) \
> + declare_constant(BREAKPOINTED) \
> + declare_constant(SLEEPING) \
> + declare_constant(ZOMBIE) \
> + \
> /******************************/ \
>    /* Klass misc. enum constants */                                        \
> /******************************/ \
> diff --git a/test/serviceability/sa/JhsdbThreadInfoTest.java b/test/serviceability/sa/JhsdbThreadInfoTest.java
> new file mode 100644
> --- /dev/null
> +++ b/test/serviceability/sa/JhsdbThreadInfoTest.java
> @@ -0,0 +1,87 @@
> +/*
> + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
> + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
> + *
> + * This code is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 only, as
> + * published by the Free Software Foundation.
> + *
> + * This code is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> + * version 2 for more details (a copy is included in the LICENSE file that
> + * accompanied this code).
> + *
> + * You should have received a copy of the GNU General Public License version
> + * 2 along with this work; if not, write to the Free Software Foundation,
> + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
> + * or visit www.oracle.com if you need additional information or have any
> + * questions.
> + */
> +
> +import jdk.test.lib.apps.LingeredApp;
> +import jdk.test.lib.JDKToolLauncher;
> +import jdk.test.lib.Platform;
> +import jdk.test.lib.process.OutputAnalyzer;
> +import jdk.test.lib.Utils;
> +
> +/*
> + * @test
> + * @library /test/lib
> + * @run main JhsdbThreadInfoTest
> + */
> +public class JhsdbThreadInfoTest {
> +
> +    public static void main(String[] args) throws Exception {
> +
> +        if (!Platform.shouldSAAttach()) {
> +            System.out.println("SA attach not expected to work - test skipped.");
> +            return;
> +        }
> +
> +        LingeredApp app = null;
> +
> +        try {
> +            app = LingeredApp.startApp(Utils.getVmOptions());
> +            System.out.println("Started LingeredApp with pid " + app.getPid());
> +
> +            JDKToolLauncher jhsdbLauncher = JDKToolLauncher.createUsingTestJDK("jhsdb");
> +
> +            jhsdbLauncher.addToolArg("jstack");
> +            jhsdbLauncher.addToolArg("--pid");
> +            jhsdbLauncher.addToolArg(Long.toString(app.getPid()));
> +
> +            ProcessBuilder pb = new ProcessBuilder();
> +            pb.command(jhsdbLauncher.getCommand());
> +            Process jhsdb = pb.start();
> +
> +            jhsdb.waitFor();
> +
> +            OutputAnalyzer out = new OutputAnalyzer(jhsdb);
> +
> +            System.out.println(out.getStdout());
> +            System.err.println(out.getStderr());
> +
> +            out.shouldMatch("\".+\" #\\d+ daemon prio=\\d+ tid=0x[0-9a-f]+ nid=0x[0-9a-f]+ .+ \\[0x[0-9a-f]+]");
> +            out.shouldMatch("\"main\" #\\d+ prio=\\d+ tid=0x[0-9a-f]+ nid=0x[0-9a-f]+ .+ \\[0x[0-9a-f]+]");
> +            out.shouldMatch("   java.lang.Thread.State: .+");
> +            out.shouldMatch("   JavaThread state: _thread_.+");
> +
> +            out.shouldNotContain("   java.lang.Thread.State: UNKNOWN");
> +            out.stderrShouldBeEmpty();
> +
> +            System.out.println("Test Completed");
> +
> +
> +        } catch (InterruptedException ie) {
> +            throw new Error("Problem awaiting the child process: " + ie, ie);
> +        } catch (Exception attachE) {
> +            throw new Error("Couldn't start jhsdb, attach to LingeredApp or match ThreadName: " + attachE);
> +
> +        } finally {
> +            LingeredApp.stopApp(app);
> +        }
> +    }
> +}
>
>
>
>
> On 2017/07/04 23:44, Yasumasa Suenaga wrote:
>> Hi Chihiro,
>>
>> Thank you for updating your patch!
>> I have a comment to printThreadInfoOn() in JavaThread.java:
>>
>>> + out.print(String.format("0x%016x",this.getAddress().asLongValue()));
>>> +    out.print(" nid=");
>>> +    out.print(String.format("0x%x ",this.getOSThread().threadId()));
>>> +    out.print(getOSThread().getThreadState().getPrintVal());
>>> +    out.print(" [");
>>> +    if( this.getLastJavaSP() == null){
>>> +      out.print(String.format("0x%016x",0L));
>>
>> You set "0x%016x" to format string for address value.
>> However, this length is changed by pointer length e.g. "0x%08x" should be set on ILP32 platforms.
>>
>> In case of Linux, Address#toString() generates platform-aware string value in DebuggerUtilities#addressValueToString(). So you can use Address#toString() if Address is not null.
>>
>>
>> Yasumasa
>>
>>
>> On 2017/07/04 0:32, chihiro ito wrote:
>>> Hi Yasumasa,
>>>
>>> Thank you for review, again.
>>>
>>>> According to JavaThread::print_on() in thread.cpp , stack address in thread dump shows top of page address.
>>>> If so, can we calculate it as below?
>>>>
>>>>   this.getLastJavaSP().andWithMask(~0xFFF)
>>>
>>> Yes, It is also correct. I modified source code to your simple one.
>>>
>>>> Are these regex correct?
>>>> Regex for SP "\\[0x[0-9a-f]+]" should be "\\[0x[0-9a-f]+\\]"
>>>> (Last backslash is missing.)
>>>
>>> ] that is not paired with [ does not need to be escaped.
>>>
>>> following 2 case it print true.
>>> System.out.println("]".matches("]"));
>>> System.out.println("]".matches("\\]"));
>>>
>>> The source code which modified the logical operation is as follows.
>>>
>>> Regards,
>>> Chihiro
>>>
>>>
>>> diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/OopUtilities.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/OopUtilities.java
>>> --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/OopUtilities.java
>>> +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/OopUtilities.java
>>> @@ -1,5 +1,5 @@
>>>   /*
>>> - * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
>>> + * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
>>>    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>>>    *
>>>    * This code is free software; you can redistribute it and/or modify it
>>> @@ -59,20 +59,20 @@
>>>     // parkBlocker field is new since 1.6
>>>     private static OopField threadParkBlockerField;
>>>
>>> +  private static IntField threadPriorityField;
>>> +  private static BooleanField threadDaemonField;
>>> +
>>>     // possible values of java_lang_Thread::ThreadStatus
>>>     private static int THREAD_STATUS_NEW;
>>> -  /*
>>> -    Other enum constants are not needed as of now. Uncomment these as and when needed.
>>>
>>> -    private static int THREAD_STATUS_RUNNABLE;
>>> -    private static int THREAD_STATUS_SLEEPING;
>>> -    private static int THREAD_STATUS_IN_OBJECT_WAIT;
>>> -    private static int THREAD_STATUS_IN_OBJECT_WAIT_TIMED;
>>> -    private static int THREAD_STATUS_PARKED;
>>> -    private static int THREAD_STATUS_PARKED_TIMED;
>>> -    private static int THREAD_STATUS_BLOCKED_ON_MONITOR_ENTER;
>>> -    private static int THREAD_STATUS_TERMINATED;
>>> -  */
>>> +  private static int THREAD_STATUS_RUNNABLE;
>>> +  private static int THREAD_STATUS_SLEEPING;
>>> +  private static int THREAD_STATUS_IN_OBJECT_WAIT;
>>> +  private static int THREAD_STATUS_IN_OBJECT_WAIT_TIMED;
>>> +  private static int THREAD_STATUS_PARKED;
>>> +  private static int THREAD_STATUS_PARKED_TIMED;
>>> +  private static int THREAD_STATUS_BLOCKED_ON_MONITOR_ENTER;
>>> +  private static int THREAD_STATUS_TERMINATED;
>>>
>>>     // java.util.concurrent.locks.AbstractOwnableSynchronizer fields
>>>     private static OopField absOwnSyncOwnerThreadField;
>>> @@ -229,20 +229,19 @@
>>>         threadStatusField = (IntField) k.findField("threadStatus", "I");
>>>         threadParkBlockerField = (OopField) k.findField("parkBlocker",
>>>                                        "Ljava/lang/Object;");
>>> +      threadPriorityField = (IntField) k.findField("priority", "I");
>>> +      threadDaemonField = (BooleanField) k.findField("daemon", "Z");
>>>         TypeDataBase db = VM.getVM().getTypeDataBase();
>>>         THREAD_STATUS_NEW = db.lookupIntConstant("java_lang_Thread::NEW").intValue();
>>> -      /*
>>> -        Other enum constants are not needed as of now. Uncomment these as and when needed.
>>>
>>> -        THREAD_STATUS_RUNNABLE = db.lookupIntConstant("java_lang_Thread::RUNNABLE").intValue();
>>> -        THREAD_STATUS_SLEEPING = db.lookupIntConstant("java_lang_Thread::SLEEPING").intValue();
>>> -        THREAD_STATUS_IN_OBJECT_WAIT = db.lookupIntConstant("java_lang_Thread::IN_OBJECT_WAIT").intValue();
>>> -        THREAD_STATUS_IN_OBJECT_WAIT_TIMED = db.lookupIntConstant("java_lang_Thread::IN_OBJECT_WAIT_TIMED").intValue();
>>> -        THREAD_STATUS_PARKED = db.lookupIntConstant("java_lang_Thread::PARKED").intValue();
>>> -        THREAD_STATUS_PARKED_TIMED = db.lookupIntConstant("java_lang_Thread::PARKED_TIMED").intValue();
>>> -        THREAD_STATUS_BLOCKED_ON_MONITOR_ENTER = db.lookupIntConstant("java_lang_Thread::BLOCKED_ON_MONITOR_ENTER").intValue();
>>> -        THREAD_STATUS_TERMINATED = db.lookupIntConstant("java_lang_Thread::TERMINATED").intValue();
>>> -      */
>>> +      THREAD_STATUS_RUNNABLE = db.lookupIntConstant("java_lang_Thread::RUNNABLE").intValue();
>>> +      THREAD_STATUS_SLEEPING = db.lookupIntConstant("java_lang_Thread::SLEEPING").intValue();
>>> +      THREAD_STATUS_IN_OBJECT_WAIT = db.lookupIntConstant("java_lang_Thread::IN_OBJECT_WAIT").intValue();
>>> +      THREAD_STATUS_IN_OBJECT_WAIT_TIMED = db.lookupIntConstant("java_lang_Thread::IN_OBJECT_WAIT_TIMED").intValue();
>>> +      THREAD_STATUS_PARKED = db.lookupIntConstant("java_lang_Thread::PARKED").intValue();
>>> +      THREAD_STATUS_PARKED_TIMED = db.lookupIntConstant("java_lang_Thread::PARKED_TIMED").intValue();
>>> +      THREAD_STATUS_BLOCKED_ON_MONITOR_ENTER = db.lookupIntConstant("java_lang_Thread::BLOCKED_ON_MONITOR_ENTER").intValue();
>>> +      THREAD_STATUS_TERMINATED = db.lookupIntConstant("java_lang_Thread::TERMINATED").intValue();
>>>
>>>         if (Assert.ASSERTS_ENABLED) {
>>>           // it is okay to miss threadStatusField, because this was
>>> @@ -331,4 +330,46 @@
>>>         return absOwnSyncOwnerThreadField.getValue(oop);
>>>       }
>>>     }
>>> +
>>> +  public static int threadOopGetPriority(Oop threadOop) {
>>> +    initThreadFields();
>>> +    if (threadPriorityField != null) {
>>> +      return threadPriorityField.getValue(threadOop);
>>> +    } else {
>>> +      return 0;
>>> +    }
>>> +  }
>>> +
>>> +  public static boolean threadOopGetDaemon(Oop threadOop) {
>>> +    initThreadFields();
>>> +    if (threadDaemonField != null) {
>>> +      return threadDaemonField.getValue(threadOop);
>>> +    } else {
>>> +      return false;
>>> +    }
>>> +  }
>>> +
>>> +  public static String threadOopGetThreadStatusName(Oop threadOop) {
>>> +    int status = OopUtilities.threadOopGetThreadStatus(threadOop);
>>> +    if( status == THREAD_STATUS_NEW ){
>>> +      return "NEW";
>>> +    }else if(status == THREAD_STATUS_RUNNABLE ){
>>> +      return "RUNNABLE";
>>> +    }else if(status == THREAD_STATUS_SLEEPING ){
>>> +      return "TIMED_WAITING (sleeping)";
>>> +    }else if(status == THREAD_STATUS_IN_OBJECT_WAIT ){
>>> +      return "WAITING (on object monitor)";
>>> +    }else if(status == THREAD_STATUS_IN_OBJECT_WAIT_TIMED ){
>>> +      return "TIMED_WAITING (on object monitor)";
>>> +    }else if(status == THREAD_STATUS_PARKED ){
>>> +      return "WAITING (parking)";
>>> +    }else if(status == THREAD_STATUS_PARKED_TIMED ){
>>> +      return "TIMED_WAITING (parking)";
>>> +    }else if(status == THREAD_STATUS_BLOCKED_ON_MONITOR_ENTER ){
>>> +      return "BLOCKED (on object monitor)";
>>> +    }else if(status == THREAD_STATUS_TERMINATED ){
>>> +      return "TERMINATED";
>>> +    }
>>> +    return "UNKNOWN";
>>> +  }
>>>   }
>>> diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java
>>> --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java
>>> +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java
>>> @@ -475,4 +475,35 @@
>>>       return access.getLastSP(addr);
>>>     }
>>>
>>> +
>>> +  public void printThreadInfoOn(PrintStream out){
>>> +
>>> +    Oop threadOop = this.getThreadObj();
>>> +
>>> +    out.print("\"");
>>> +    out.print(this.getThreadName());
>>> +    out.print("\" #");
>>> +    out.print(OopUtilities.threadOopGetTID(threadOop));
>>> +    if( OopUtilities.threadOopGetDaemon(threadOop) ){
>>> +      out.print(" daemon");
>>> +    }
>>> +    out.print(" prio=");
>>> +    out.print(OopUtilities.threadOopGetPriority(threadOop));
>>> +    out.print(" tid=");
>>> + out.print(String.format("0x%016x",this.getAddress().asLongValue()));
>>> +    out.print(" nid=");
>>> +    out.print(String.format("0x%x ",this.getOSThread().threadId()));
>>> +    out.print(getOSThread().getThreadState().getPrintVal());
>>> +    out.print(" [");
>>> +    if( this.getLastJavaSP() == null){
>>> +      out.print(String.format("0x%016x",0L));
>>> +    } else {
>>> +      out.print(this.getLastJavaSP().andWithMask(~0xFFF));
>>> +    }
>>> +    out.println("]");
>>> +    out.print("   java.lang.Thread.State: ");
>>> + out.println(OopUtilities.threadOopGetThreadStatusName(threadOop));
>>> +    out.print("   JavaThread state: _thread_");
>>> + out.println(this.getThreadState().toString().toLowerCase());
>>> +  }
>>>   }
>>> diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/OSThread.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/OSThread.java
>>> --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/OSThread.java
>>> +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/OSThread.java
>>> @@ -1,5 +1,5 @@
>>>   /*
>>> - * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
>>> + * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved.
>>>    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>>>    *
>>>    * This code is free software; you can redistribute it and/or modify it
>>> @@ -33,6 +33,19 @@
>>>   public class OSThread extends VMObject {
>>>       private static JIntField interruptedField;
>>>       private static Field threadIdField;
>>> +    private static CIntegerField threadStateField;
>>> +
>>> +    // ThreadStates read from underlying process
>>> +    private static int ALLOCATED;
>>> +    private static int INITIALIZED;
>>> +    private static int RUNNABLE;
>>> +    private static int MONITOR_WAIT;
>>> +    private static int CONDVAR_WAIT;
>>> +    private static int OBJECT_WAIT;
>>> +    private static int BREAKPOINTED;
>>> +    private static int SLEEPING;
>>> +    private static int ZOMBIE;
>>> +
>>>       static {
>>>           VM.registerVMInitializedObserver(new Observer() {
>>>               public void update(Observable o, Object data) {
>>> @@ -45,6 +58,17 @@
>>>           Type type = db.lookupType("OSThread");
>>>           interruptedField = type.getJIntField("_interrupted");
>>>           threadIdField = type.getField("_thread_id");
>>> +        threadStateField = type.getCIntegerField("_state");
>>> +
>>> +        ALLOCATED = db.lookupIntConstant("ALLOCATED").intValue();
>>> +        INITIALIZED = db.lookupIntConstant("INITIALIZED").intValue();
>>> +        RUNNABLE = db.lookupIntConstant("RUNNABLE").intValue();
>>> +        MONITOR_WAIT = db.lookupIntConstant("MONITOR_WAIT").intValue();
>>> +        CONDVAR_WAIT = db.lookupIntConstant("CONDVAR_WAIT").intValue();
>>> +        OBJECT_WAIT = db.lookupIntConstant("OBJECT_WAIT").intValue();
>>> +        BREAKPOINTED = db.lookupIntConstant("BREAKPOINTED").intValue();
>>> +        SLEEPING = db.lookupIntConstant("SLEEPING").intValue();
>>> +        ZOMBIE = db.lookupIntConstant("ZOMBIE").intValue();
>>>       }
>>>
>>>       public OSThread(Address addr) {
>>> @@ -59,4 +83,28 @@
>>>           return threadIdField.getJInt(addr);
>>>       }
>>>
>>> +    public ThreadState getThreadState() {
>>> +        int val = (int)threadStateField.getValue(addr);
>>> +        if (val ==  ALLOCATED) {
>>> +            return ThreadState.ALLOCATED;
>>> +        } else if (val ==  INITIALIZED) {
>>> +            return ThreadState.INITIALIZED;
>>> +        } else if (val ==  RUNNABLE) {
>>> +            return ThreadState.RUNNABLE;
>>> +        } else if (val ==  MONITOR_WAIT) {
>>> +            return ThreadState.MONITOR_WAIT;
>>> +        } else if (val ==  CONDVAR_WAIT) {
>>> +            return ThreadState.CONDVAR_WAIT;
>>> +        } else if (val ==  OBJECT_WAIT) {
>>> +            return ThreadState.OBJECT_WAIT;
>>> +        } else if (val ==  BREAKPOINTED) {
>>> +            return ThreadState.BREAKPOINTED;
>>> +        } else if (val ==  SLEEPING) {
>>> +            return ThreadState.SLEEPING;
>>> +        } else if (val ==  ZOMBIE) {
>>> +            return ThreadState.ZOMBIE;
>>> +        } else {
>>> +            throw new RuntimeException("Illegal thread state " + val);
>>> +        }
>>> +    }
>>>   }
>>> diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadState.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadState.java
>>> new file mode 100644
>>> --- /dev/null
>>> +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadState.java
>>> @@ -0,0 +1,60 @@
>>> +/*
>>> + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
>>> + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>>> + *
>>> + * This code is free software; you can redistribute it and/or modify it
>>> + * under the terms of the GNU General Public License version 2 only, as
>>> + * published by the Free Software Foundation.
>>> + *
>>> + * This code is distributed in the hope that it will be useful, but WITHOUT
>>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
>>> + * version 2 for more details (a copy is included in the LICENSE file that
>>> + * accompanied this code).
>>> + *
>>> + * You should have received a copy of the GNU General Public License version
>>> + * 2 along with this work; if not, write to the Free Software Foundation,
>>> + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
>>> + *
>>> + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
>>> + * or visit www.oracle.com if you need additional information or have any
>>> + * questions.
>>> + */
>>> +
>>> +package sun.jvm.hotspot.runtime;
>>> +
>>> +/** This is a type-safe enum mirroring the ThreadState enum in
>>> + osThread.hpp. The conversion between the underlying ints
>>> + and these values is done in OSThread. */
>>> +
>>> +public class ThreadState {
>>> +
>>> +    private String printVal;
>>> +
>>> +    /** Memory has been allocated but not initialized */
>>> +    public static final ThreadState ALLOCATED = new ThreadState("allocated");
>>> +    /** The thread has been initialized but yet started */
>>> +    public static final ThreadState INITIALIZED = new ThreadState("initialized");
>>> +    /** Has been started and is runnable, but not necessarily running */
>>> +    public static final ThreadState RUNNABLE = new ThreadState("runnable");
>>> +    /** Waiting on a contended monitor lock */
>>> +    public static final ThreadState MONITOR_WAIT = new ThreadState("waiting for monitor entry");
>>> +    /** Waiting on a condition variable */
>>> +    public static final ThreadState CONDVAR_WAIT = new ThreadState("waiting on condition");
>>> +    /** Waiting on an Object.wait() call */
>>> +    public static final ThreadState OBJECT_WAIT = new ThreadState("in Object.wait()");
>>> +    /** Suspended at breakpoint */
>>> +    public static final ThreadState BREAKPOINTED = new ThreadState("at breakpoint");
>>> +    /** Thread.sleep() */
>>> +    public static final ThreadState SLEEPING = new ThreadState("sleeping");
>>> +    /** All done, but not reclaimed yet */
>>> +    public static final ThreadState ZOMBIE = new ThreadState("zombie");
>>> +
>>> +    private ThreadState(String printVal){
>>> +        this.printVal = printVal;
>>> +    }
>>> +
>>> +    public String getPrintVal() {
>>> +        return printVal;
>>> +    }
>>> +}
>>> diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java
>>> --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java
>>> +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java
>>> @@ -1,5 +1,5 @@
>>>   /*
>>> - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
>>> + * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
>>>    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>>>    *
>>>    * This code is free software; you can redistribute it and/or modify it
>>> @@ -88,6 +88,10 @@
>>>                  out.print("----------------- ");
>>>                  out.print(th);
>>>                  out.println(" -----------------");
>>> +               JavaThread jthread = (JavaThread) proxyToThread.get(th);
>>> +               if (jthread != null) {
>>> +                  jthread.printThreadInfoOn(out);
>>> +               }
>>>                  while (f != null) {
>>>                     ClosestSymbol sym = f.closestSymbolToPC();
>>>                     Address pc = f.pc();
>>> diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java
>>> --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java
>>> +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java
>>> @@ -1,5 +1,5 @@
>>>   /*
>>> - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
>>> + * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
>>>    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>>>    *
>>>    * This code is free software; you can redistribute it and/or modify it
>>> @@ -74,14 +74,7 @@
>>>               int i = 1;
>>>               for (JavaThread cur = threads.first(); cur != null; cur = cur.next(), i++) {
>>>                   if (cur.isJavaThread()) {
>>> -                    Address sp = cur.getLastJavaSP();
>>> -                    tty.print("Thread ");
>>> -                    cur.printThreadIDOn(tty);
>>> -                    tty.print(": (state = " + cur.getThreadState());
>>> -                    if (verbose) {
>>> -                        tty.println(", current Java SP = " + sp);
>>> -                    }
>>> -                    tty.println(')');
>>> +                    cur.printThreadInfoOn(tty);
>>>                       try {
>>>                           for (JavaVFrame vf = cur.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) {
>>>                               Method method = vf.getMethod();
>>> diff --git a/src/share/vm/runtime/vmStructs.cpp b/src/share/vm/runtime/vmStructs.cpp
>>> --- a/src/share/vm/runtime/vmStructs.cpp
>>> +++ b/src/share/vm/runtime/vmStructs.cpp
>>> @@ -981,6 +981,7 @@
>>> /************/ \
>>> \
>>>     volatile_nonstatic_field(OSThread, _interrupted, jint)                                  \
>>> +  volatile_nonstatic_field(OSThread, _state, ThreadState)                                 \
>>> \
>>> /************************/ \
>>>     /* OopMap and OopMapSet */ \
>>> @@ -2186,6 +2187,7 @@
>>> declare_integer_type(Generation::Name) \
>>> declare_integer_type(InstanceKlass::ClassState) \
>>> declare_integer_type(JavaThreadState) \
>>> + declare_integer_type(ThreadState) \
>>> declare_integer_type(Location::Type) \
>>> declare_integer_type(Location::Where) \
>>> declare_integer_type(Flag::Flags) \
>>> @@ -2443,6 +2445,20 @@
>>> declare_constant(JavaThread::_not_terminated) \
>>> declare_constant(JavaThread::_thread_exiting) \
>>> \
>>> + /*******************/ \
>>> +  /* JavaThreadState */                                                   \
>>> + /*******************/ \
>>> + \
>>> + declare_constant(ALLOCATED) \
>>> + declare_constant(INITIALIZED) \
>>> + declare_constant(RUNNABLE) \
>>> + declare_constant(MONITOR_WAIT) \
>>> + declare_constant(CONDVAR_WAIT) \
>>> + declare_constant(OBJECT_WAIT) \
>>> + declare_constant(BREAKPOINTED) \
>>> + declare_constant(SLEEPING) \
>>> + declare_constant(ZOMBIE) \
>>> + \
>>> /******************************/ \
>>>     /* Klass misc. enum constants */                                        \
>>> /******************************/ \
>>> diff --git a/test/serviceability/sa/JhsdbThreadInfoTest.java b/test/serviceability/sa/JhsdbThreadInfoTest.java
>>> new file mode 100644
>>> --- /dev/null
>>> +++ b/test/serviceability/sa/JhsdbThreadInfoTest.java
>>> @@ -0,0 +1,87 @@
>>> +/*
>>> + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
>>> + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>>> + *
>>> + * This code is free software; you can redistribute it and/or modify it
>>> + * under the terms of the GNU General Public License version 2 only, as
>>> + * published by the Free Software Foundation.
>>> + *
>>> + * This code is distributed in the hope that it will be useful, but WITHOUT
>>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
>>> + * version 2 for more details (a copy is included in the LICENSE file that
>>> + * accompanied this code).
>>> + *
>>> + * You should have received a copy of the GNU General Public License version
>>> + * 2 along with this work; if not, write to the Free Software Foundation,
>>> + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
>>> + *
>>> + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
>>> + * or visit www.oracle.com if you need additional information or have any
>>> + * questions.
>>> + */
>>> +
>>> +import jdk.test.lib.apps.LingeredApp;
>>> +import jdk.test.lib.JDKToolLauncher;
>>> +import jdk.test.lib.Platform;
>>> +import jdk.test.lib.process.OutputAnalyzer;
>>> +import jdk.test.lib.Utils;
>>> +
>>> +/*
>>> + * @test
>>> + * @library /test/lib
>>> + * @run main JhsdbThreadInfoTest
>>> + */
>>> +public class JhsdbThreadInfoTest {
>>> +
>>> +    public static void main(String[] args) throws Exception {
>>> +
>>> +        if (!Platform.shouldSAAttach()) {
>>> +            System.out.println("SA attach not expected to work - test skipped.");
>>> +            return;
>>> +        }
>>> +
>>> +        LingeredApp app = null;
>>> +
>>> +        try {
>>> +            app = LingeredApp.startApp(Utils.getVmOptions());
>>> +            System.out.println("Started LingeredApp with pid " + app.getPid());
>>> +
>>> +            JDKToolLauncher jhsdbLauncher = JDKToolLauncher.createUsingTestJDK("jhsdb");
>>> +
>>> +            jhsdbLauncher.addToolArg("jstack");
>>> +            jhsdbLauncher.addToolArg("--pid");
>>> + jhsdbLauncher.addToolArg(Long.toString(app.getPid()));
>>> +
>>> +            ProcessBuilder pb = new ProcessBuilder();
>>> +            pb.command(jhsdbLauncher.getCommand());
>>> +            Process jhsdb = pb.start();
>>> +
>>> +            jhsdb.waitFor();
>>> +
>>> +            OutputAnalyzer out = new OutputAnalyzer(jhsdb);
>>> +
>>> +            System.out.println(out.getStdout());
>>> +            System.err.println(out.getStderr());
>>> +
>>> +            out.shouldMatch("\".+\" #\\d+ daemon prio=\\d+ tid=0x[0-9a-f]+ nid=0x[0-9a-f]+ .+ \\[0x[0-9a-f]+]");
>>> +            out.shouldMatch("\"main\" #\\d+ prio=\\d+ tid=0x[0-9a-f]+ nid=0x[0-9a-f]+ .+ \\[0x[0-9a-f]+]");
>>> +            out.shouldMatch("   java.lang.Thread.State: .+");
>>> +            out.shouldMatch("   JavaThread state: _thread_.+");
>>> +
>>> +            out.shouldNotContain("   java.lang.Thread.State: UNKNOWN");
>>> +            out.stderrShouldBeEmpty();
>>> +
>>> +            System.out.println("Test Completed");
>>> +
>>> +
>>> +        } catch (InterruptedException ie) {
>>> +            throw new Error("Problem awaiting the child process: " + ie, ie);
>>> +        } catch (Exception attachE) {
>>> +            throw new Error("Couldn't start jhsdb, attach to LingeredApp or match ThreadName: " + attachE);
>>> +
>>> +        } finally {
>>> +            LingeredApp.stopApp(app);
>>> +        }
>>> +    }
>>> +}
>>>
>>>
>>>
>>>
>>> On 2017/07/02 21:44, Yasumasa Suenaga wrote:
>>>> Hi Chihiro,
>>>>
>>>>
>>>> printThreadInfoOn() in JavaThread.java:
>>>>> +      Address maskAddress = this.getLastJavaSP().andWithMask(0xFFF);
>>>>> + out.print(this.getLastJavaSP().xorWithMask(maskAddress.asLongValue()));
>>>>
>>>> IMHO it is complex a bit.
>>>> According to JavaThread::print_on() in thread.cpp , stack address in thread dump shows top of page address.
>>>> If so, can we calculate it as below?
>>>>
>>>>   this.getLastJavaSP().andWithMask(~0xFFF)
>>>>
>>>>
>>>> JhsdbThreadInfoTest.java:
>>>>> +            out.shouldMatch("\".+\" #\\d+ daemon prio=\\d+ tid=0x[0-9a-f]+ nid=0x[0-9a-f]+ .+ \\[0x[0-9a-f]+]");
>>>>> +            out.shouldMatch("\"main\" #\\d+ prio=\\d+ tid=0x[0-9a-f]+ nid=0x[0-9a-f]+ .+ \\[0x[0-9a-f]+]");
>>>>
>>>> Are these regex correct?
>>>> Regex for SP "\\[0x[0-9a-f]+]" should be "\\[0x[0-9a-f]+\\]"
>>>> (Last backslash is missing.)
>>>>
>>>>
>>>> Thanks,
>>>>
>>>> Yasumasa
>>>>
>>>>
>>>> On 2017/07/02 16:43, chihiro ito wrote:
>>>>> Hi Yasumasa,
>>>>>
>>>>> Thank you for your review. I modified source code following your advice.
>>>>> I applied this to latest source code and passed jtreg.
>>>>>
>>>>> Could somebody possibly be sponsor and commit this as cito ?
>>>>>
>>>>> Regards,
>>>>> Chihiro
>>>>>
>>>>> diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/OopUtilities.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/OopUtilities.java
>>>>> --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/OopUtilities.java
>>>>> +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/OopUtilities.java
>>>>> @@ -1,5 +1,5 @@
>>>>>   /*
>>>>> - * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
>>>>> + * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
>>>>>    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>>>>>    *
>>>>>    * This code is free software; you can redistribute it and/or modify it
>>>>> @@ -59,20 +59,20 @@
>>>>>     // parkBlocker field is new since 1.6
>>>>>     private static OopField threadParkBlockerField;
>>>>>
>>>>> +  private static IntField threadPriorityField;
>>>>> +  private static BooleanField threadDaemonField;
>>>>> +
>>>>>     // possible values of java_lang_Thread::ThreadStatus
>>>>>     private static int THREAD_STATUS_NEW;
>>>>> -  /*
>>>>> -    Other enum constants are not needed as of now. Uncomment these as and when needed.
>>>>>
>>>>> -    private static int THREAD_STATUS_RUNNABLE;
>>>>> -    private static int THREAD_STATUS_SLEEPING;
>>>>> -    private static int THREAD_STATUS_IN_OBJECT_WAIT;
>>>>> -    private static int THREAD_STATUS_IN_OBJECT_WAIT_TIMED;
>>>>> -    private static int THREAD_STATUS_PARKED;
>>>>> -    private static int THREAD_STATUS_PARKED_TIMED;
>>>>> -    private static int THREAD_STATUS_BLOCKED_ON_MONITOR_ENTER;
>>>>> -    private static int THREAD_STATUS_TERMINATED;
>>>>> -  */
>>>>> +  private static int THREAD_STATUS_RUNNABLE;
>>>>> +  private static int THREAD_STATUS_SLEEPING;
>>>>> +  private static int THREAD_STATUS_IN_OBJECT_WAIT;
>>>>> +  private static int THREAD_STATUS_IN_OBJECT_WAIT_TIMED;
>>>>> +  private static int THREAD_STATUS_PARKED;
>>>>> +  private static int THREAD_STATUS_PARKED_TIMED;
>>>>> +  private static int THREAD_STATUS_BLOCKED_ON_MONITOR_ENTER;
>>>>> +  private static int THREAD_STATUS_TERMINATED;
>>>>>
>>>>>     // java.util.concurrent.locks.AbstractOwnableSynchronizer fields
>>>>>     private static OopField absOwnSyncOwnerThreadField;
>>>>> @@ -229,20 +229,19 @@
>>>>>         threadStatusField = (IntField) k.findField("threadStatus", "I");
>>>>>         threadParkBlockerField = (OopField) k.findField("parkBlocker",
>>>>> "Ljava/lang/Object;");
>>>>> +      threadPriorityField = (IntField) k.findField("priority", "I");
>>>>> +      threadDaemonField = (BooleanField) k.findField("daemon", "Z");
>>>>>         TypeDataBase db = VM.getVM().getTypeDataBase();
>>>>>         THREAD_STATUS_NEW = db.lookupIntConstant("java_lang_Thread::NEW").intValue();
>>>>> -      /*
>>>>> -        Other enum constants are not needed as of now. Uncomment these as and when needed.
>>>>>
>>>>> -        THREAD_STATUS_RUNNABLE = db.lookupIntConstant("java_lang_Thread::RUNNABLE").intValue();
>>>>> -        THREAD_STATUS_SLEEPING = db.lookupIntConstant("java_lang_Thread::SLEEPING").intValue();
>>>>> -        THREAD_STATUS_IN_OBJECT_WAIT = db.lookupIntConstant("java_lang_Thread::IN_OBJECT_WAIT").intValue();
>>>>> -        THREAD_STATUS_IN_OBJECT_WAIT_TIMED = db.lookupIntConstant("java_lang_Thread::IN_OBJECT_WAIT_TIMED").intValue();
>>>>> -        THREAD_STATUS_PARKED = db.lookupIntConstant("java_lang_Thread::PARKED").intValue();
>>>>> -        THREAD_STATUS_PARKED_TIMED = db.lookupIntConstant("java_lang_Thread::PARKED_TIMED").intValue();
>>>>> -        THREAD_STATUS_BLOCKED_ON_MONITOR_ENTER = db.lookupIntConstant("java_lang_Thread::BLOCKED_ON_MONITOR_ENTER").intValue();
>>>>> -        THREAD_STATUS_TERMINATED = db.lookupIntConstant("java_lang_Thread::TERMINATED").intValue();
>>>>> -      */
>>>>> +      THREAD_STATUS_RUNNABLE = db.lookupIntConstant("java_lang_Thread::RUNNABLE").intValue();
>>>>> +      THREAD_STATUS_SLEEPING = db.lookupIntConstant("java_lang_Thread::SLEEPING").intValue();
>>>>> +      THREAD_STATUS_IN_OBJECT_WAIT = db.lookupIntConstant("java_lang_Thread::IN_OBJECT_WAIT").intValue();
>>>>> +      THREAD_STATUS_IN_OBJECT_WAIT_TIMED = db.lookupIntConstant("java_lang_Thread::IN_OBJECT_WAIT_TIMED").intValue();
>>>>> +      THREAD_STATUS_PARKED = db.lookupIntConstant("java_lang_Thread::PARKED").intValue();
>>>>> +      THREAD_STATUS_PARKED_TIMED = db.lookupIntConstant("java_lang_Thread::PARKED_TIMED").intValue();
>>>>> +      THREAD_STATUS_BLOCKED_ON_MONITOR_ENTER = db.lookupIntConstant("java_lang_Thread::BLOCKED_ON_MONITOR_ENTER").intValue();
>>>>> +      THREAD_STATUS_TERMINATED = db.lookupIntConstant("java_lang_Thread::TERMINATED").intValue();
>>>>>
>>>>>         if (Assert.ASSERTS_ENABLED) {
>>>>>           // it is okay to miss threadStatusField, because this was
>>>>> @@ -331,4 +330,46 @@
>>>>>         return absOwnSyncOwnerThreadField.getValue(oop);
>>>>>       }
>>>>>     }
>>>>> +
>>>>> +  public static int threadOopGetPriority(Oop threadOop) {
>>>>> +    initThreadFields();
>>>>> +    if (threadPriorityField != null) {
>>>>> +      return threadPriorityField.getValue(threadOop);
>>>>> +    } else {
>>>>> +      return 0;
>>>>> +    }
>>>>> +  }
>>>>> +
>>>>> +  public static boolean threadOopGetDaemon(Oop threadOop) {
>>>>> +    initThreadFields();
>>>>> +    if (threadDaemonField != null) {
>>>>> +      return threadDaemonField.getValue(threadOop);
>>>>> +    } else {
>>>>> +      return false;
>>>>> +    }
>>>>> +  }
>>>>> +
>>>>> +  public static String threadOopGetThreadStatusName(Oop threadOop) {
>>>>> +    int status = OopUtilities.threadOopGetThreadStatus(threadOop);
>>>>> +    if( status == THREAD_STATUS_NEW ){
>>>>> +      return "NEW";
>>>>> +    }else if(status == THREAD_STATUS_RUNNABLE ){
>>>>> +      return "RUNNABLE";
>>>>> +    }else if(status == THREAD_STATUS_SLEEPING ){
>>>>> +      return "TIMED_WAITING (sleeping)";
>>>>> +    }else if(status == THREAD_STATUS_IN_OBJECT_WAIT ){
>>>>> +      return "WAITING (on object monitor)";
>>>>> +    }else if(status == THREAD_STATUS_IN_OBJECT_WAIT_TIMED ){
>>>>> +      return "TIMED_WAITING (on object monitor)";
>>>>> +    }else if(status == THREAD_STATUS_PARKED ){
>>>>> +      return "WAITING (parking)";
>>>>> +    }else if(status == THREAD_STATUS_PARKED_TIMED ){
>>>>> +      return "TIMED_WAITING (parking)";
>>>>> +    }else if(status == THREAD_STATUS_BLOCKED_ON_MONITOR_ENTER ){
>>>>> +      return "BLOCKED (on object monitor)";
>>>>> +    }else if(status == THREAD_STATUS_TERMINATED ){
>>>>> +      return "TERMINATED";
>>>>> +    }
>>>>> +    return "UNKNOWN";
>>>>> +  }
>>>>>   }
>>>>> diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java
>>>>> --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java
>>>>> +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java
>>>>> @@ -475,4 +475,36 @@
>>>>>       return access.getLastSP(addr);
>>>>>     }
>>>>>
>>>>> +
>>>>> +  public void printThreadInfoOn(PrintStream out){
>>>>> +
>>>>> +    Oop threadOop = this.getThreadObj();
>>>>> +
>>>>> +    out.print("\"");
>>>>> +    out.print(this.getThreadName());
>>>>> +    out.print("\" #");
>>>>> +    out.print(OopUtilities.threadOopGetTID(threadOop));
>>>>> +    if( OopUtilities.threadOopGetDaemon(threadOop) ){
>>>>> +      out.print(" daemon");
>>>>> +    }
>>>>> +    out.print(" prio=");
>>>>> + out.print(OopUtilities.threadOopGetPriority(threadOop));
>>>>> +    out.print(" tid=");
>>>>> + out.print(String.format("0x%016x",this.getAddress().asLongValue()));
>>>>> +    out.print(" nid=");
>>>>> +    out.print(String.format("0x%x ",this.getOSThread().threadId()));
>>>>> + out.print(getOSThread().getThreadState().getPrintVal());
>>>>> +    out.print(" [");
>>>>> +    if( this.getLastJavaSP() == null){
>>>>> +      out.print(String.format("0x%016x",0L));
>>>>> +    } else {
>>>>> +      Address maskAddress = this.getLastJavaSP().andWithMask(0xFFF);
>>>>> + out.print(this.getLastJavaSP().xorWithMask(maskAddress.asLongValue()));
>>>>> +    }
>>>>> +    out.println("]");
>>>>> +    out.print("   java.lang.Thread.State: ");
>>>>> + out.println(OopUtilities.threadOopGetThreadStatusName(threadOop));
>>>>> +    out.print("   JavaThread state: _thread_");
>>>>> + out.println(this.getThreadState().toString().toLowerCase());
>>>>> +  }
>>>>>   }
>>>>> diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/OSThread.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/OSThread.java
>>>>> --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/OSThread.java
>>>>> +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/OSThread.java
>>>>> @@ -1,5 +1,5 @@
>>>>>   /*
>>>>> - * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
>>>>> + * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved.
>>>>>    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>>>>>    *
>>>>>    * This code is free software; you can redistribute it and/or modify it
>>>>> @@ -33,6 +33,19 @@
>>>>>   public class OSThread extends VMObject {
>>>>>       private static JIntField interruptedField;
>>>>>       private static Field threadIdField;
>>>>> +    private static CIntegerField threadStateField;
>>>>> +
>>>>> +    // ThreadStates read from underlying process
>>>>> +    private static int ALLOCATED;
>>>>> +    private static int INITIALIZED;
>>>>> +    private static int RUNNABLE;
>>>>> +    private static int MONITOR_WAIT;
>>>>> +    private static int CONDVAR_WAIT;
>>>>> +    private static int OBJECT_WAIT;
>>>>> +    private static int BREAKPOINTED;
>>>>> +    private static int SLEEPING;
>>>>> +    private static int ZOMBIE;
>>>>> +
>>>>>       static {
>>>>>           VM.registerVMInitializedObserver(new Observer() {
>>>>>               public void update(Observable o, Object data) {
>>>>> @@ -45,6 +58,17 @@
>>>>>           Type type = db.lookupType("OSThread");
>>>>>           interruptedField = type.getJIntField("_interrupted");
>>>>>           threadIdField = type.getField("_thread_id");
>>>>> +        threadStateField = type.getCIntegerField("_state");
>>>>> +
>>>>> +        ALLOCATED = db.lookupIntConstant("ALLOCATED").intValue();
>>>>> +        INITIALIZED = db.lookupIntConstant("INITIALIZED").intValue();
>>>>> +        RUNNABLE = db.lookupIntConstant("RUNNABLE").intValue();
>>>>> +        MONITOR_WAIT = db.lookupIntConstant("MONITOR_WAIT").intValue();
>>>>> +        CONDVAR_WAIT = db.lookupIntConstant("CONDVAR_WAIT").intValue();
>>>>> +        OBJECT_WAIT = db.lookupIntConstant("OBJECT_WAIT").intValue();
>>>>> +        BREAKPOINTED = db.lookupIntConstant("BREAKPOINTED").intValue();
>>>>> +        SLEEPING = db.lookupIntConstant("SLEEPING").intValue();
>>>>> +        ZOMBIE = db.lookupIntConstant("ZOMBIE").intValue();
>>>>>       }
>>>>>
>>>>>       public OSThread(Address addr) {
>>>>> @@ -59,4 +83,28 @@
>>>>>           return threadIdField.getJInt(addr);
>>>>>       }
>>>>>
>>>>> +    public ThreadState getThreadState() {
>>>>> +        int val = (int)threadStateField.getValue(addr);
>>>>> +        if (val ==  ALLOCATED) {
>>>>> +            return ThreadState.ALLOCATED;
>>>>> +        } else if (val ==  INITIALIZED) {
>>>>> +            return ThreadState.INITIALIZED;
>>>>> +        } else if (val ==  RUNNABLE) {
>>>>> +            return ThreadState.RUNNABLE;
>>>>> +        } else if (val ==  MONITOR_WAIT) {
>>>>> +            return ThreadState.MONITOR_WAIT;
>>>>> +        } else if (val ==  CONDVAR_WAIT) {
>>>>> +            return ThreadState.CONDVAR_WAIT;
>>>>> +        } else if (val ==  OBJECT_WAIT) {
>>>>> +            return ThreadState.OBJECT_WAIT;
>>>>> +        } else if (val ==  BREAKPOINTED) {
>>>>> +            return ThreadState.BREAKPOINTED;
>>>>> +        } else if (val ==  SLEEPING) {
>>>>> +            return ThreadState.SLEEPING;
>>>>> +        } else if (val ==  ZOMBIE) {
>>>>> +            return ThreadState.ZOMBIE;
>>>>> +        } else {
>>>>> +            throw new RuntimeException("Illegal thread state " + val);
>>>>> +        }
>>>>> +    }
>>>>>   }
>>>>> diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadState.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadState.java
>>>>> new file mode 100644
>>>>> --- /dev/null
>>>>> +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadState.java
>>>>> @@ -0,0 +1,60 @@
>>>>> +/*
>>>>> + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
>>>>> + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>>>>> + *
>>>>> + * This code is free software; you can redistribute it and/or modify it
>>>>> + * under the terms of the GNU General Public License version 2 only, as
>>>>> + * published by the Free Software Foundation.
>>>>> + *
>>>>> + * This code is distributed in the hope that it will be useful, but WITHOUT
>>>>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>>>>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
>>>>> + * version 2 for more details (a copy is included in the LICENSE file that
>>>>> + * accompanied this code).
>>>>> + *
>>>>> + * You should have received a copy of the GNU General Public License version
>>>>> + * 2 along with this work; if not, write to the Free Software Foundation,
>>>>> + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
>>>>> + *
>>>>> + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
>>>>> + * or visit www.oracle.com if you need additional information or have any
>>>>> + * questions.
>>>>> + */
>>>>> +
>>>>> +package sun.jvm.hotspot.runtime;
>>>>> +
>>>>> +/** This is a type-safe enum mirroring the ThreadState enum in
>>>>> + osThread.hpp. The conversion between the underlying ints
>>>>> + and these values is done in OSThread. */
>>>>> +
>>>>> +public class ThreadState {
>>>>> +
>>>>> +    private String printVal;
>>>>> +
>>>>> +    /** Memory has been allocated but not initialized */
>>>>> +    public static final ThreadState ALLOCATED = new ThreadState("allocated");
>>>>> +    /** The thread has been initialized but yet started */
>>>>> +    public static final ThreadState INITIALIZED = new ThreadState("initialized");
>>>>> +    /** Has been started and is runnable, but not necessarily running */
>>>>> +    public static final ThreadState RUNNABLE = new ThreadState("runnable");
>>>>> +    /** Waiting on a contended monitor lock */
>>>>> +    public static final ThreadState MONITOR_WAIT = new ThreadState("waiting for monitor entry");
>>>>> +    /** Waiting on a condition variable */
>>>>> +    public static final ThreadState CONDVAR_WAIT = new ThreadState("waiting on condition");
>>>>> +    /** Waiting on an Object.wait() call */
>>>>> +    public static final ThreadState OBJECT_WAIT = new ThreadState("in Object.wait()");
>>>>> +    /** Suspended at breakpoint */
>>>>> +    public static final ThreadState BREAKPOINTED = new ThreadState("at breakpoint");
>>>>> +    /** Thread.sleep() */
>>>>> +    public static final ThreadState SLEEPING = new ThreadState("sleeping");
>>>>> +    /** All done, but not reclaimed yet */
>>>>> +    public static final ThreadState ZOMBIE = new ThreadState("zombie");
>>>>> +
>>>>> +    private ThreadState(String printVal){
>>>>> +        this.printVal = printVal;
>>>>> +    }
>>>>> +
>>>>> +    public String getPrintVal() {
>>>>> +        return printVal;
>>>>> +    }
>>>>> +}
>>>>> diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java
>>>>> --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java
>>>>> +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java
>>>>> @@ -1,5 +1,5 @@
>>>>>   /*
>>>>> - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
>>>>> + * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
>>>>>    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>>>>>    *
>>>>>    * This code is free software; you can redistribute it and/or modify it
>>>>> @@ -88,6 +88,10 @@
>>>>>                  out.print("----------------- ");
>>>>>                  out.print(th);
>>>>>                  out.println(" -----------------");
>>>>> +               JavaThread jthread = (JavaThread) proxyToThread.get(th);
>>>>> +               if (jthread != null) {
>>>>> +                  jthread.printThreadInfoOn(out);
>>>>> +               }
>>>>>                  while (f != null) {
>>>>>                     ClosestSymbol sym = f.closestSymbolToPC();
>>>>>                     Address pc = f.pc();
>>>>> diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java
>>>>> --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java
>>>>> +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java
>>>>> @@ -1,5 +1,5 @@
>>>>>   /*
>>>>> - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
>>>>> + * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
>>>>>    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>>>>>    *
>>>>>    * This code is free software; you can redistribute it and/or modify it
>>>>> @@ -74,14 +74,7 @@
>>>>>               int i = 1;
>>>>>               for (JavaThread cur = threads.first(); cur != null; cur = cur.next(), i++) {
>>>>>                   if (cur.isJavaThread()) {
>>>>> -                    Address sp = cur.getLastJavaSP();
>>>>> -                    tty.print("Thread ");
>>>>> -                    cur.printThreadIDOn(tty);
>>>>> -                    tty.print(": (state = " + cur.getThreadState());
>>>>> -                    if (verbose) {
>>>>> -                        tty.println(", current Java SP = " + sp);
>>>>> -                    }
>>>>> -                    tty.println(')');
>>>>> +                    cur.printThreadInfoOn(tty);
>>>>>                       try {
>>>>>                           for (JavaVFrame vf = cur.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) {
>>>>>                               Method method = vf.getMethod();
>>>>> diff --git a/src/share/vm/runtime/vmStructs.cpp b/src/share/vm/runtime/vmStructs.cpp
>>>>> --- a/src/share/vm/runtime/vmStructs.cpp
>>>>> +++ b/src/share/vm/runtime/vmStructs.cpp
>>>>> @@ -981,6 +981,7 @@
>>>>> /************/ \
>>>>> \
>>>>>     volatile_nonstatic_field(OSThread, _interrupted, jint)                                  \
>>>>> +  volatile_nonstatic_field(OSThread, _state, ThreadState)                                 \
>>>>> \
>>>>> /************************/ \
>>>>>     /* OopMap and OopMapSet */ \
>>>>> @@ -2186,6 +2187,7 @@
>>>>> declare_integer_type(Generation::Name) \
>>>>> declare_integer_type(InstanceKlass::ClassState) \
>>>>> declare_integer_type(JavaThreadState) \
>>>>> + declare_integer_type(ThreadState) \
>>>>> declare_integer_type(Location::Type) \
>>>>> declare_integer_type(Location::Where) \
>>>>> declare_integer_type(Flag::Flags) \
>>>>> @@ -2443,6 +2445,20 @@
>>>>> declare_constant(JavaThread::_not_terminated) \
>>>>> declare_constant(JavaThread::_thread_exiting) \
>>>>> \
>>>>> + /*******************/ \
>>>>> +  /* JavaThreadState */                                                   \
>>>>> + /*******************/ \
>>>>> + \
>>>>> + declare_constant(ALLOCATED) \
>>>>> + declare_constant(INITIALIZED) \
>>>>> + declare_constant(RUNNABLE) \
>>>>> + declare_constant(MONITOR_WAIT) \
>>>>> + declare_constant(CONDVAR_WAIT) \
>>>>> + declare_constant(OBJECT_WAIT) \
>>>>> + declare_constant(BREAKPOINTED) \
>>>>> + declare_constant(SLEEPING) \
>>>>> + declare_constant(ZOMBIE) \
>>>>> + \
>>>>> /******************************/ \
>>>>>     /* Klass misc. enum constants */                                        \
>>>>> /******************************/ \
>>>>> diff --git a/test/serviceability/sa/JhsdbThreadInfoTest.java b/test/serviceability/sa/JhsdbThreadInfoTest.java
>>>>> new file mode 100644
>>>>> --- /dev/null
>>>>> +++ b/test/serviceability/sa/JhsdbThreadInfoTest.java
>>>>> @@ -0,0 +1,87 @@
>>>>> +/*
>>>>> + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
>>>>> + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>>>>> + *
>>>>> + * This code is free software; you can redistribute it and/or modify it
>>>>> + * under the terms of the GNU General Public License version 2 only, as
>>>>> + * published by the Free Software Foundation.
>>>>> + *
>>>>> + * This code is distributed in the hope that it will be useful, but WITHOUT
>>>>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>>>>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
>>>>> + * version 2 for more details (a copy is included in the LICENSE file that
>>>>> + * accompanied this code).
>>>>> + *
>>>>> + * You should have received a copy of the GNU General Public License version
>>>>> + * 2 along with this work; if not, write to the Free Software Foundation,
>>>>> + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
>>>>> + *
>>>>> + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
>>>>> + * or visit www.oracle.com if you need additional information or have any
>>>>> + * questions.
>>>>> + */
>>>>> +
>>>>> +import jdk.test.lib.apps.LingeredApp;
>>>>> +import jdk.test.lib.JDKToolLauncher;
>>>>> +import jdk.test.lib.Platform;
>>>>> +import jdk.test.lib.process.OutputAnalyzer;
>>>>> +import jdk.test.lib.Utils;
>>>>> +
>>>>> +/*
>>>>> + * @test
>>>>> + * @library /test/lib
>>>>> + * @run main JhsdbThreadInfoTest
>>>>> + */
>>>>> +public class JhsdbThreadInfoTest {
>>>>> +
>>>>> +    public static void main(String[] args) throws Exception {
>>>>> +
>>>>> +        if (!Platform.shouldSAAttach()) {
>>>>> +            System.out.println("SA attach not expected to work - test skipped.");
>>>>> +            return;
>>>>> +        }
>>>>> +
>>>>> +        LingeredApp app = null;
>>>>> +
>>>>> +        try {
>>>>> +            app = LingeredApp.startApp(Utils.getVmOptions());
>>>>> +            System.out.println("Started LingeredApp with pid " + app.getPid());
>>>>> +
>>>>> +            JDKToolLauncher jhsdbLauncher = JDKToolLauncher.createUsingTestJDK("jhsdb");
>>>>> +
>>>>> +            jhsdbLauncher.addToolArg("jstack");
>>>>> +            jhsdbLauncher.addToolArg("--pid");
>>>>> + jhsdbLauncher.addToolArg(Long.toString(app.getPid()));
>>>>> +
>>>>> +            ProcessBuilder pb = new ProcessBuilder();
>>>>> +            pb.command(jhsdbLauncher.getCommand());
>>>>> +            Process jhsdb = pb.start();
>>>>> +
>>>>> +            jhsdb.waitFor();
>>>>> +
>>>>> +            OutputAnalyzer out = new OutputAnalyzer(jhsdb);
>>>>> +
>>>>> +            System.out.println(out.getStdout());
>>>>> +            System.err.println(out.getStderr());
>>>>> +
>>>>> +            out.shouldMatch("\".+\" #\\d+ daemon prio=\\d+ tid=0x[0-9a-f]+ nid=0x[0-9a-f]+ .+ \\[0x[0-9a-f]+]");
>>>>> +            out.shouldMatch("\"main\" #\\d+ prio=\\d+ tid=0x[0-9a-f]+ nid=0x[0-9a-f]+ .+ \\[0x[0-9a-f]+]");
>>>>> +            out.shouldMatch("   java.lang.Thread.State: .+");
>>>>> +            out.shouldMatch("   JavaThread state: _thread_.+");
>>>>> +
>>>>> +            out.shouldNotContain(" java.lang.Thread.State: UNKNOWN");
>>>>> +            out.stderrShouldBeEmpty();
>>>>> +
>>>>> +            System.out.println("Test Completed");
>>>>> +
>>>>> +
>>>>> +        } catch (InterruptedException ie) {
>>>>> +            throw new Error("Problem awaiting the child process: " + ie, ie);
>>>>> +        } catch (Exception attachE) {
>>>>> +            throw new Error("Couldn't start jhsdb, attach to LingeredApp or match ThreadName: " + attachE);
>>>>> +
>>>>> +        } finally {
>>>>> +            LingeredApp.stopApp(app);
>>>>> +        }
>>>>> +    }
>>>>> +}
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> On 2017/06/29 7:40, Yasumasa Suenaga wrote:
>>>>>> Hi chihiro,
>>>>>>
>>>>>> getThreadState() in OSThread.java:
>>>>>>
>>>>>>>> +        } else if (val == BREAKPOINTED) {
>>>>>>>> +            return ThreadState.BREAKPOINTED;
>>>>>>>> +        } else if (val ==  BREAKPOINTED) {
>>>>>>>> +            return ThreadState.BREAKPOINTED;
>>>>>>
>>>>>> These conditions are duplicated.
>>>>>>
>>>>>>
>>>>>> Please upload webrev if you can :-)
>>>>>>
>>>>>>
>>>>>> Yasumasa
>>>>>>
>>>>>>
>>>>>> On 2017/06/29 0:02, chihiro ito wrote:
>>>>>>> Hi all,
>>>>>>>
>>>>>>> In last week, I've posted review request [1].
>>>>>>> Could you possibly review for this following small change? If review is ok, please commit this as cito.
>>>>>>>
>>>>>>> [1] http://mail.openjdk.java.net/pipermail/serviceability-dev/2017-June/021430.html
>>>>>>>
>>>>>>> Thanks,
>>>>>>> Chihiro (Contributer)
>>>>>>>
>>>>>>> On 2017/06/18 13:02, chihiro ito wrote:
>>>>>>>> At first I thought to print just each thread name, but I tried to make it as similar as possible to JStack as following.
>>>>>>>>
>>>>>>>> Mixed mode:
>>>>>>>> ----------------- 26476 -----------------
>>>>>>>> "main" #1 prio=5 tid=0x00007f6894019000 nid=0x676c waiting on condition [0x00007f689b7ae000]
>>>>>>>>    java.lang.Thread.State: TIMED_WAITING (sleeping)
>>>>>>>>    JavaThread state: _thread_blocked
>>>>>>>> 0x00007f689b185a82    __pthread_cond_timedwait + 0x132
>>>>>>>>
>>>>>>>> No mixed mode:
>>>>>>>> "main" #1 prio=5 tid=0x00007f6894019000 nid=0x676c waiting on condition [0x00007f689b7ae000]
>>>>>>>>    java.lang.Thread.State: TIMED_WAITING (sleeping)
>>>>>>>>    JavaThread state: _thread_blocked
>>>>>>>>  - java.lang.Thread.sleep(long) @bci=0 (Interpreted frame)
>>>>>>>>
>>>>>>>>
>>>>>>>> This change passed a test by jtreg.
>>>>>>>>
>>>>>>>> SOURCE_HOME=/home/user/repo/jdk10-hs
>>>>>>>> jtreg -dir:${SOURCE_HOME}/hotspot/test -testjdk:${SOURCE_HOME}/build/linux-x86_64-normal-server-slowdebug/jdk/ serviceability/sa/JhsdbThreadInfoTest.java
>>>>>>>> Test results: passed: 1
>>>>>>>>
>>>>>>>>
>>>>>>>> Source:
>>>>>>>> diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/OopUtilities.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/OopUtilities.java
>>>>>>>> --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/OopUtilities.java
>>>>>>>> +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/OopUtilities.java
>>>>>>>> @@ -1,5 +1,5 @@
>>>>>>>>  /*
>>>>>>>> - * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
>>>>>>>> + * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
>>>>>>>>   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>>>>>>>>   *
>>>>>>>>   * This code is free software; you can redistribute it and/or modify it
>>>>>>>> @@ -59,20 +59,20 @@
>>>>>>>>    // parkBlocker field is new since 1.6
>>>>>>>>    private static OopField threadParkBlockerField;
>>>>>>>>
>>>>>>>> +  private static IntField threadPriorityField;
>>>>>>>> +  private static BooleanField threadDaemonField;
>>>>>>>> +
>>>>>>>>    // possible values of java_lang_Thread::ThreadStatus
>>>>>>>>    private static int THREAD_STATUS_NEW;
>>>>>>>> -  /*
>>>>>>>> -    Other enum constants are not needed as of now. Uncomment these as and when needed.
>>>>>>>>
>>>>>>>> -    private static int THREAD_STATUS_RUNNABLE;
>>>>>>>> -    private static int THREAD_STATUS_SLEEPING;
>>>>>>>> -    private static int THREAD_STATUS_IN_OBJECT_WAIT;
>>>>>>>> -    private static int THREAD_STATUS_IN_OBJECT_WAIT_TIMED;
>>>>>>>> -    private static int THREAD_STATUS_PARKED;
>>>>>>>> -    private static int THREAD_STATUS_PARKED_TIMED;
>>>>>>>> -    private static int THREAD_STATUS_BLOCKED_ON_MONITOR_ENTER;
>>>>>>>> -    private static int THREAD_STATUS_TERMINATED;
>>>>>>>> -  */
>>>>>>>> +  private static int THREAD_STATUS_RUNNABLE;
>>>>>>>> +  private static int THREAD_STATUS_SLEEPING;
>>>>>>>> +  private static int THREAD_STATUS_IN_OBJECT_WAIT;
>>>>>>>> +  private static int THREAD_STATUS_IN_OBJECT_WAIT_TIMED;
>>>>>>>> +  private static int THREAD_STATUS_PARKED;
>>>>>>>> +  private static int THREAD_STATUS_PARKED_TIMED;
>>>>>>>> +  private static int THREAD_STATUS_BLOCKED_ON_MONITOR_ENTER;
>>>>>>>> +  private static int THREAD_STATUS_TERMINATED;
>>>>>>>>
>>>>>>>>    // java.util.concurrent.locks.AbstractOwnableSynchronizer fields
>>>>>>>>    private static OopField absOwnSyncOwnerThreadField;
>>>>>>>> @@ -229,20 +229,19 @@
>>>>>>>>        threadStatusField = (IntField) k.findField("threadStatus", "I");
>>>>>>>>        threadParkBlockerField = (OopField) k.findField("parkBlocker",
>>>>>>>> "Ljava/lang/Object;");
>>>>>>>> +      threadPriorityField = (IntField) k.findField("priority", "I");
>>>>>>>> +      threadDaemonField = (BooleanField) k.findField("daemon", "Z");
>>>>>>>>        TypeDataBase db = VM.getVM().getTypeDataBase();
>>>>>>>>        THREAD_STATUS_NEW = db.lookupIntConstant("java_lang_Thread::NEW").intValue();
>>>>>>>> -      /*
>>>>>>>> -        Other enum constants are not needed as of now. Uncomment these as and when needed.
>>>>>>>>
>>>>>>>> -        THREAD_STATUS_RUNNABLE = db.lookupIntConstant("java_lang_Thread::RUNNABLE").intValue();
>>>>>>>> -        THREAD_STATUS_SLEEPING = db.lookupIntConstant("java_lang_Thread::SLEEPING").intValue();
>>>>>>>> -        THREAD_STATUS_IN_OBJECT_WAIT = db.lookupIntConstant("java_lang_Thread::IN_OBJECT_WAIT").intValue();
>>>>>>>> -        THREAD_STATUS_IN_OBJECT_WAIT_TIMED = db.lookupIntConstant("java_lang_Thread::IN_OBJECT_WAIT_TIMED").intValue();
>>>>>>>> -        THREAD_STATUS_PARKED = db.lookupIntConstant("java_lang_Thread::PARKED").intValue();
>>>>>>>> -        THREAD_STATUS_PARKED_TIMED = db.lookupIntConstant("java_lang_Thread::PARKED_TIMED").intValue();
>>>>>>>> -        THREAD_STATUS_BLOCKED_ON_MONITOR_ENTER = db.lookupIntConstant("java_lang_Thread::BLOCKED_ON_MONITOR_ENTER").intValue();
>>>>>>>> -        THREAD_STATUS_TERMINATED = db.lookupIntConstant("java_lang_Thread::TERMINATED").intValue();
>>>>>>>> -      */
>>>>>>>> +      THREAD_STATUS_RUNNABLE = db.lookupIntConstant("java_lang_Thread::RUNNABLE").intValue();
>>>>>>>> +      THREAD_STATUS_SLEEPING = db.lookupIntConstant("java_lang_Thread::SLEEPING").intValue();
>>>>>>>> +      THREAD_STATUS_IN_OBJECT_WAIT = db.lookupIntConstant("java_lang_Thread::IN_OBJECT_WAIT").intValue();
>>>>>>>> +      THREAD_STATUS_IN_OBJECT_WAIT_TIMED = db.lookupIntConstant("java_lang_Thread::IN_OBJECT_WAIT_TIMED").intValue();
>>>>>>>> +      THREAD_STATUS_PARKED = db.lookupIntConstant("java_lang_Thread::PARKED").intValue();
>>>>>>>> +      THREAD_STATUS_PARKED_TIMED = db.lookupIntConstant("java_lang_Thread::PARKED_TIMED").intValue();
>>>>>>>> +      THREAD_STATUS_BLOCKED_ON_MONITOR_ENTER = db.lookupIntConstant("java_lang_Thread::BLOCKED_ON_MONITOR_ENTER").intValue();
>>>>>>>> +      THREAD_STATUS_TERMINATED = db.lookupIntConstant("java_lang_Thread::TERMINATED").intValue();
>>>>>>>>
>>>>>>>>        if (Assert.ASSERTS_ENABLED) {
>>>>>>>>          // it is okay to miss threadStatusField, because this was
>>>>>>>> @@ -331,4 +330,46 @@
>>>>>>>>        return absOwnSyncOwnerThreadField.getValue(oop);
>>>>>>>>      }
>>>>>>>>    }
>>>>>>>> +
>>>>>>>> +  public static int threadOopGetPriority(Oop threadOop) {
>>>>>>>> +    initThreadFields();
>>>>>>>> +    if (threadPriorityField != null) {
>>>>>>>> +      return threadPriorityField.getValue(threadOop);
>>>>>>>> +    } else {
>>>>>>>> +      return 0;
>>>>>>>> +    }
>>>>>>>> +  }
>>>>>>>> +
>>>>>>>> +  public static boolean threadOopGetDaemon(Oop threadOop) {
>>>>>>>> +    initThreadFields();
>>>>>>>> +    if (threadDaemonField != null) {
>>>>>>>> +      return threadDaemonField.getValue(threadOop);
>>>>>>>> +    } else {
>>>>>>>> +      return false;
>>>>>>>> +    }
>>>>>>>> +  }
>>>>>>>> +
>>>>>>>> +  public static String threadOopGetThreadStatusName(Oop threadOop) {
>>>>>>>> +    int status = OopUtilities.threadOopGetThreadStatus(threadOop);
>>>>>>>> +    if( status == THREAD_STATUS_NEW ){
>>>>>>>> +      return "NEW";
>>>>>>>> +    }else if(status == THREAD_STATUS_RUNNABLE ){
>>>>>>>> +      return "RUNNABLE";
>>>>>>>> +    }else if(status == THREAD_STATUS_SLEEPING ){
>>>>>>>> +      return "TIMED_WAITING (sleeping)";
>>>>>>>> +    }else if(status == THREAD_STATUS_IN_OBJECT_WAIT ){
>>>>>>>> +      return "WAITING (on object monitor)";
>>>>>>>> +    }else if(status == THREAD_STATUS_IN_OBJECT_WAIT_TIMED ){
>>>>>>>> +      return "TIMED_WAITING (on object monitor)";
>>>>>>>> +    }else if(status == THREAD_STATUS_PARKED ){
>>>>>>>> +      return "WAITING (parking)";
>>>>>>>> +    }else if(status == THREAD_STATUS_PARKED_TIMED ){
>>>>>>>> +      return "TIMED_WAITING (parking)";
>>>>>>>> +    }else if(status == THREAD_STATUS_BLOCKED_ON_MONITOR_ENTER ){
>>>>>>>> +      return "BLOCKED (on object monitor)";
>>>>>>>> +    }else if(status == THREAD_STATUS_TERMINATED ){
>>>>>>>> +      return "TERMINATED";
>>>>>>>> +    }
>>>>>>>> +    return "UNKNOWN";
>>>>>>>> +  }
>>>>>>>>  }
>>>>>>>> diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java
>>>>>>>> --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java
>>>>>>>> +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java
>>>>>>>> @@ -475,4 +475,36 @@
>>>>>>>>      return access.getLastSP(addr);
>>>>>>>>    }
>>>>>>>>
>>>>>>>> +
>>>>>>>> +  public void printThreadInfoOn(PrintStream out){
>>>>>>>> +
>>>>>>>> +    Oop threadOop = this.getThreadObj();
>>>>>>>> +
>>>>>>>> +    out.print("\"");
>>>>>>>> +    out.print(this.getThreadName());
>>>>>>>> +    out.print("\" #");
>>>>>>>> + out.print(OopUtilities.threadOopGetTID(threadOop));
>>>>>>>> +    if( OopUtilities.threadOopGetDaemon(threadOop) ){
>>>>>>>> +      out.print(" daemon");
>>>>>>>> +    }
>>>>>>>> +    out.print(" prio=");
>>>>>>>> + out.print(OopUtilities.threadOopGetPriority(threadOop));
>>>>>>>> +    out.print(" tid=");
>>>>>>>> + out.print(String.format("0x%016x",this.getAddress().asLongValue()));
>>>>>>>> +    out.print(" nid=");
>>>>>>>> +    out.print(String.format("0x%x ",this.getOSThread().threadId()));
>>>>>>>> + out.print(getOSThread().getThreadState().getPrintVal());
>>>>>>>> +    out.print(" [");
>>>>>>>> +    if( this.getLastJavaSP() == null){
>>>>>>>> +      out.print(String.format("0x%016x",0L));
>>>>>>>> +    } else {
>>>>>>>> +      Address maskAddress = this.getLastJavaSP().andWithMask(0xFFF);
>>>>>>>> + out.print(this.getLastJavaSP().xorWithMask(maskAddress.asLongValue()));
>>>>>>>> +    }
>>>>>>>> +    out.println("]");
>>>>>>>> +    out.print("   java.lang.Thread.State: ");
>>>>>>>> + out.println(OopUtilities.threadOopGetThreadStatusName(threadOop));
>>>>>>>> +    out.print("   JavaThread state: _thread_");
>>>>>>>> + out.println(this.getThreadState().toString().toLowerCase());
>>>>>>>> +  }
>>>>>>>>  }
>>>>>>>> diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/OSThread.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/OSThread.java
>>>>>>>> --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/OSThread.java
>>>>>>>> +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/OSThread.java
>>>>>>>> @@ -1,5 +1,5 @@
>>>>>>>>  /*
>>>>>>>> - * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
>>>>>>>> + * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved.
>>>>>>>>   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>>>>>>>>   *
>>>>>>>>   * This code is free software; you can redistribute it and/or modify it
>>>>>>>> @@ -33,6 +33,19 @@
>>>>>>>>  public class OSThread extends VMObject {
>>>>>>>>      private static JIntField interruptedField;
>>>>>>>>      private static Field threadIdField;
>>>>>>>> +    private static CIntegerField threadStateField;
>>>>>>>> +
>>>>>>>> +    // ThreadStates read from underlying process
>>>>>>>> +    private static int ALLOCATED;
>>>>>>>> +    private static int INITIALIZED;
>>>>>>>> +    private static int RUNNABLE;
>>>>>>>> +    private static int MONITOR_WAIT;
>>>>>>>> +    private static int CONDVAR_WAIT;
>>>>>>>> +    private static int OBJECT_WAIT;
>>>>>>>> +    private static int BREAKPOINTED;
>>>>>>>> +    private static int SLEEPING;
>>>>>>>> +    private static int ZOMBIE;
>>>>>>>> +
>>>>>>>>      static {
>>>>>>>>          VM.registerVMInitializedObserver(new Observer() {
>>>>>>>>              public void update(Observable o, Object data) {
>>>>>>>> @@ -45,6 +58,17 @@
>>>>>>>>          Type type = db.lookupType("OSThread");
>>>>>>>>          interruptedField = type.getJIntField("_interrupted");
>>>>>>>>          threadIdField = type.getField("_thread_id");
>>>>>>>> +        threadStateField = type.getCIntegerField("_state");
>>>>>>>> +
>>>>>>>> +        ALLOCATED = db.lookupIntConstant("ALLOCATED").intValue();
>>>>>>>> +        INITIALIZED = db.lookupIntConstant("INITIALIZED").intValue();
>>>>>>>> +        RUNNABLE = db.lookupIntConstant("RUNNABLE").intValue();
>>>>>>>> +        MONITOR_WAIT = db.lookupIntConstant("MONITOR_WAIT").intValue();
>>>>>>>> +        CONDVAR_WAIT = db.lookupIntConstant("CONDVAR_WAIT").intValue();
>>>>>>>> +        OBJECT_WAIT = db.lookupIntConstant("OBJECT_WAIT").intValue();
>>>>>>>> +        BREAKPOINTED = db.lookupIntConstant("BREAKPOINTED").intValue();
>>>>>>>> +        SLEEPING = db.lookupIntConstant("SLEEPING").intValue();
>>>>>>>> +        ZOMBIE = db.lookupIntConstant("ZOMBIE").intValue();
>>>>>>>>      }
>>>>>>>>
>>>>>>>>      public OSThread(Address addr) {
>>>>>>>> @@ -59,4 +83,30 @@
>>>>>>>>          return threadIdField.getJInt(addr);
>>>>>>>>      }
>>>>>>>>
>>>>>>>> +    public ThreadState getThreadState() {
>>>>>>>> +        int val = (int)threadStateField.getValue(addr);
>>>>>>>> +        if (val ==  ALLOCATED) {
>>>>>>>> +            return ThreadState.ALLOCATED;
>>>>>>>> +        } else if (val ==  INITIALIZED) {
>>>>>>>> +            return ThreadState.INITIALIZED;
>>>>>>>> +        } else if (val ==  RUNNABLE) {
>>>>>>>> +            return ThreadState.RUNNABLE;
>>>>>>>> +        } else if (val ==  MONITOR_WAIT) {
>>>>>>>> +            return ThreadState.MONITOR_WAIT;
>>>>>>>> +        } else if (val ==  CONDVAR_WAIT) {
>>>>>>>> +            return ThreadState.CONDVAR_WAIT;
>>>>>>>> +        } else if (val ==  OBJECT_WAIT) {
>>>>>>>> +            return ThreadState.OBJECT_WAIT;
>>>>>>>> +        } else if (val ==  BREAKPOINTED) {
>>>>>>>> +            return ThreadState.BREAKPOINTED;
>>>>>>>> +        } else if (val ==  BREAKPOINTED) {
>>>>>>>> +            return ThreadState.BREAKPOINTED;
>>>>>>>> +        } else if (val ==  SLEEPING) {
>>>>>>>> +            return ThreadState.SLEEPING;
>>>>>>>> +        } else if (val ==  ZOMBIE) {
>>>>>>>> +            return ThreadState.ZOMBIE;
>>>>>>>> +        } else {
>>>>>>>> +            throw new RuntimeException("Illegal thread state " + val);
>>>>>>>> +        }
>>>>>>>> +    }
>>>>>>>>  }
>>>>>>>> diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadState.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadState.java
>>>>>>>> new file mode 100644
>>>>>>>> --- /dev/null
>>>>>>>> +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadState.java
>>>>>>>> @@ -0,0 +1,60 @@
>>>>>>>> +/*
>>>>>>>> + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
>>>>>>>> + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>>>>>>>> + *
>>>>>>>> + * This code is free software; you can redistribute it and/or modify it
>>>>>>>> + * under the terms of the GNU General Public License version 2 only, as
>>>>>>>> + * published by the Free Software Foundation.
>>>>>>>> + *
>>>>>>>> + * This code is distributed in the hope that it will be useful, but WITHOUT
>>>>>>>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>>>>>>>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
>>>>>>>> + * version 2 for more details (a copy is included in the LICENSE file that
>>>>>>>> + * accompanied this code).
>>>>>>>> + *
>>>>>>>> + * You should have received a copy of the GNU General Public License version
>>>>>>>> + * 2 along with this work; if not, write to the Free Software Foundation,
>>>>>>>> + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
>>>>>>>> + *
>>>>>>>> + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
>>>>>>>> + * or visit www.oracle.com if you need additional information or have any
>>>>>>>> + * questions.
>>>>>>>> + */
>>>>>>>> +
>>>>>>>> +package sun.jvm.hotspot.runtime;
>>>>>>>> +
>>>>>>>> +/** This is a type-safe enum mirroring the ThreadState enum in
>>>>>>>> + osThread.hpp. The conversion between the underlying ints
>>>>>>>> + and these values is done in OSThread. */
>>>>>>>> +
>>>>>>>> +public class ThreadState {
>>>>>>>> +
>>>>>>>> +    private String printVal;
>>>>>>>> +
>>>>>>>> +    /** Memory has been allocated but not initialized */
>>>>>>>> +    public static final ThreadState ALLOCATED = new ThreadState("allocated");
>>>>>>>> +    /** The thread has been initialized but yet started */
>>>>>>>> +    public static final ThreadState INITIALIZED = new ThreadState("initialized");
>>>>>>>> +    /** Has been started and is runnable, but not necessarily running */
>>>>>>>> +    public static final ThreadState RUNNABLE = new ThreadState("runnable");
>>>>>>>> +    /** Waiting on a contended monitor lock */
>>>>>>>> +    public static final ThreadState MONITOR_WAIT = new ThreadState("waiting for monitor entry");
>>>>>>>> +    /** Waiting on a condition variable */
>>>>>>>> +    public static final ThreadState CONDVAR_WAIT = new ThreadState("waiting on condition");
>>>>>>>> +    /** Waiting on an Object.wait() call */
>>>>>>>> +    public static final ThreadState OBJECT_WAIT = new ThreadState("in Object.wait()");
>>>>>>>> +    /** Suspended at breakpoint */
>>>>>>>> +    public static final ThreadState BREAKPOINTED = new ThreadState("at breakpoint");
>>>>>>>> +    /** Thread.sleep() */
>>>>>>>> +    public static final ThreadState SLEEPING = new ThreadState("sleeping");
>>>>>>>> +    /** All done, but not reclaimed yet */
>>>>>>>> +    public static final ThreadState ZOMBIE = new ThreadState("zombie");
>>>>>>>> +
>>>>>>>> +    private ThreadState(String printVal){
>>>>>>>> +        this.printVal = printVal;
>>>>>>>> +    }
>>>>>>>> +
>>>>>>>> +    public String getPrintVal() {
>>>>>>>> +        return printVal;
>>>>>>>> +    }
>>>>>>>> +}
>>>>>>>> diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java
>>>>>>>> --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java
>>>>>>>> +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java
>>>>>>>> @@ -1,5 +1,5 @@
>>>>>>>>  /*
>>>>>>>> - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
>>>>>>>> + * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
>>>>>>>>   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>>>>>>>>   *
>>>>>>>>   * This code is free software; you can redistribute it and/or modify it
>>>>>>>> @@ -88,6 +88,10 @@
>>>>>>>>                 out.print("----------------- ");
>>>>>>>>                 out.print(th);
>>>>>>>>                 out.println(" -----------------");
>>>>>>>> +               JavaThread jthread = (JavaThread) proxyToThread.get(th);
>>>>>>>> +               if (jthread != null) {
>>>>>>>> +                  jthread.printThreadInfoOn(out);
>>>>>>>> +               }
>>>>>>>>                 while (f != null) {
>>>>>>>>                    ClosestSymbol sym = f.closestSymbolToPC();
>>>>>>>>                    Address pc = f.pc();
>>>>>>>> diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java
>>>>>>>> --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java
>>>>>>>> +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java
>>>>>>>> @@ -1,5 +1,5 @@
>>>>>>>>  /*
>>>>>>>> - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
>>>>>>>> + * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
>>>>>>>>   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>>>>>>>>   *
>>>>>>>>   * This code is free software; you can redistribute it and/or modify it
>>>>>>>> @@ -74,14 +74,7 @@
>>>>>>>>              int i = 1;
>>>>>>>>              for (JavaThread cur = threads.first(); cur != null; cur = cur.next(), i++) {
>>>>>>>>                  if (cur.isJavaThread()) {
>>>>>>>> -                    Address sp = cur.getLastJavaSP();
>>>>>>>> -                    tty.print("Thread ");
>>>>>>>> -                    cur.printThreadIDOn(tty);
>>>>>>>> -                    tty.print(": (state = " + cur.getThreadState());
>>>>>>>> -                    if (verbose) {
>>>>>>>> -                        tty.println(", current Java SP = " + sp);
>>>>>>>> -                    }
>>>>>>>> -                    tty.println(')');
>>>>>>>> +                    cur.printThreadInfoOn(tty);
>>>>>>>>                      try {
>>>>>>>>                          for (JavaVFrame vf = cur.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) {
>>>>>>>>                              Method method = vf.getMethod();
>>>>>>>> diff --git a/src/share/vm/runtime/vmStructs.cpp b/src/share/vm/runtime/vmStructs.cpp
>>>>>>>> --- a/src/share/vm/runtime/vmStructs.cpp
>>>>>>>> +++ b/src/share/vm/runtime/vmStructs.cpp
>>>>>>>> @@ -981,6 +981,7 @@
>>>>>>>> /************/ \
>>>>>>>> \
>>>>>>>>    volatile_nonstatic_field(OSThread, _interrupted, jint)                                  \
>>>>>>>> +  volatile_nonstatic_field(OSThread, _state, ThreadState)                                 \
>>>>>>>> \
>>>>>>>> /************************/ \
>>>>>>>>    /* OopMap and OopMapSet */ \
>>>>>>>> @@ -2186,6 +2187,7 @@
>>>>>>>> declare_integer_type(Generation::Name) \
>>>>>>>> declare_integer_type(InstanceKlass::ClassState) \
>>>>>>>> declare_integer_type(JavaThreadState) \
>>>>>>>> + declare_integer_type(ThreadState) \
>>>>>>>> declare_integer_type(Location::Type) \
>>>>>>>> declare_integer_type(Location::Where) \
>>>>>>>> declare_integer_type(Flag::Flags) \
>>>>>>>> @@ -2443,6 +2445,20 @@
>>>>>>>> declare_constant(JavaThread::_not_terminated) \
>>>>>>>> declare_constant(JavaThread::_thread_exiting) \
>>>>>>>> \
>>>>>>>> + /*******************/ \
>>>>>>>> +  /* JavaThreadState */                                                   \
>>>>>>>> + /*******************/ \
>>>>>>>> + \
>>>>>>>> + declare_constant(ALLOCATED) \
>>>>>>>> + declare_constant(INITIALIZED) \
>>>>>>>> + declare_constant(RUNNABLE) \
>>>>>>>> + declare_constant(MONITOR_WAIT) \
>>>>>>>> + declare_constant(CONDVAR_WAIT) \
>>>>>>>> + declare_constant(OBJECT_WAIT) \
>>>>>>>> + declare_constant(BREAKPOINTED) \
>>>>>>>> + declare_constant(SLEEPING) \
>>>>>>>> + declare_constant(ZOMBIE) \
>>>>>>>> + \
>>>>>>>> /******************************/ \
>>>>>>>>    /* Klass misc. enum constants */                                        \
>>>>>>>> /******************************/ \
>>>>>>>> diff --git a/test/serviceability/sa/JhsdbThreadInfoTest.java b/test/serviceability/sa/JhsdbThreadInfoTest.java
>>>>>>>> new file mode 100644
>>>>>>>> --- /dev/null
>>>>>>>> +++ b/test/serviceability/sa/JhsdbThreadInfoTest.java
>>>>>>>> @@ -0,0 +1,87 @@
>>>>>>>> +/*
>>>>>>>> + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
>>>>>>>> + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>>>>>>>> + *
>>>>>>>> + * This code is free software; you can redistribute it and/or modify it
>>>>>>>> + * under the terms of the GNU General Public License version 2 only, as
>>>>>>>> + * published by the Free Software Foundation.
>>>>>>>> + *
>>>>>>>> + * This code is distributed in the hope that it will be useful, but WITHOUT
>>>>>>>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>>>>>>>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
>>>>>>>> + * version 2 for more details (a copy is included in the LICENSE file that
>>>>>>>> + * accompanied this code).
>>>>>>>> + *
>>>>>>>> + * You should have received a copy of the GNU General Public License version
>>>>>>>> + * 2 along with this work; if not, write to the Free Software Foundation,
>>>>>>>> + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
>>>>>>>> + *
>>>>>>>> + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
>>>>>>>> + * or visit www.oracle.com if you need additional information or have any
>>>>>>>> + * questions.
>>>>>>>> + */
>>>>>>>> +
>>>>>>>> +import jdk.test.lib.apps.LingeredApp;
>>>>>>>> +import jdk.test.lib.JDKToolLauncher;
>>>>>>>> +import jdk.test.lib.Platform;
>>>>>>>> +import jdk.test.lib.process.OutputAnalyzer;
>>>>>>>> +import jdk.test.lib.Utils;
>>>>>>>> +
>>>>>>>> +/*
>>>>>>>> + * @test
>>>>>>>> + * @library /test/lib
>>>>>>>> + * @run main JhsdbThreadInfoTest
>>>>>>>> + */
>>>>>>>> +public class JhsdbThreadInfoTest {
>>>>>>>> +
>>>>>>>> +    public static void main(String[] args) throws Exception {
>>>>>>>> +
>>>>>>>> +        if (!Platform.shouldSAAttach()) {
>>>>>>>> +            System.out.println("SA attach not expected to work - test skipped.");
>>>>>>>> +            return;
>>>>>>>> +        }
>>>>>>>> +
>>>>>>>> +        LingeredApp app = null;
>>>>>>>> +
>>>>>>>> +        try {
>>>>>>>> +            app = LingeredApp.startApp(Utils.getVmOptions());
>>>>>>>> +            System.out.println("Started LingeredApp with pid " + app.getPid());
>>>>>>>> +
>>>>>>>> +            JDKToolLauncher jhsdbLauncher = JDKToolLauncher.createUsingTestJDK("jhsdb");
>>>>>>>> +
>>>>>>>> +            jhsdbLauncher.addToolArg("jstack");
>>>>>>>> +            jhsdbLauncher.addToolArg("--pid");
>>>>>>>> + jhsdbLauncher.addToolArg(Long.toString(app.getPid()));
>>>>>>>> +
>>>>>>>> +            ProcessBuilder pb = new ProcessBuilder();
>>>>>>>> +            pb.command(jhsdbLauncher.getCommand());
>>>>>>>> +            Process jhsdb = pb.start();
>>>>>>>> +
>>>>>>>> +            jhsdb.waitFor();
>>>>>>>> +
>>>>>>>> +            OutputAnalyzer out = new OutputAnalyzer(jhsdb);
>>>>>>>> +
>>>>>>>> +            System.out.println(out.getStdout());
>>>>>>>> +            System.err.println(out.getStderr());
>>>>>>>> +
>>>>>>>> +            out.shouldMatch("\".+\" #\\d+ daemon prio=\\d+ tid=0x[0-9a-f]+ nid=0x[0-9a-f]+ .+ \\[0x[0-9a-f]+]");
>>>>>>>> +            out.shouldMatch("\"main\" #\\d+ prio=\\d+ tid=0x[0-9a-f]+ nid=0x[0-9a-f]+ .+ \\[0x[0-9a-f]+]");
>>>>>>>> +            out.shouldMatch(" java.lang.Thread.State: .+");
>>>>>>>> +            out.shouldMatch("   JavaThread state: _thread_.+");
>>>>>>>> +
>>>>>>>> +            out.shouldNotContain(" java.lang.Thread.State: UNKNOWN");
>>>>>>>> +            out.stderrShouldBeEmpty();
>>>>>>>> +
>>>>>>>> +            System.out.println("Test Completed");
>>>>>>>> +
>>>>>>>> +
>>>>>>>> +        } catch (InterruptedException ie) {
>>>>>>>> +            throw new Error("Problem awaiting the child process: " + ie, ie);
>>>>>>>> +        } catch (Exception attachE) {
>>>>>>>> +            throw new Error("Couldn't start jhsdb, attach to LingeredApp or match ThreadName: " + attachE);
>>>>>>>> +
>>>>>>>> +        } finally {
>>>>>>>> +            LingeredApp.stopApp(app);
>>>>>>>> +        }
>>>>>>>> +    }
>>>>>>>> +}
>>>>>>>>
>>>>>>>>
>>>>>>>> Regards,
>>>>>>>> Chihiro
>>>>>>>>
>>>>>>>>
>>>>>>>> On 2017/06/14 16:51, Bernd Eckenfels wrote:
>>>>>>>>> I don't understand why this format is totally different from the normal stack traces? At least the header with the stack names could be similar?
>>>>>>>>>
>>>>>>>>> Gruss
>>>>>>>>> Bernd
>>>>>>>>> --
>>>>>>>>> https://urldefense.proofpoint.com/v2/url?u=http-3A__bernd.eckenfels.net&d=DwICaQ&c=RoP1YumCXCgaWHvlZYR8PQcxBKCX5YTpkKY057SbK10&r=0SCyhNQIV2jPt0aEruqsRB6bzVcIXHTDh1GkXLV1dyY&m=3QRaQqXxp0PcpNUQsiJOAlmzxeN3O9PyZoFxlIPpsUs&s=KMibjgBgQ9DJ0ddSGSJrvH7PZMz4zGnH-CZml-iRTMM&e= ------------------------------------------------------------------------
>>>>>>>>> *From:* serviceability-dev <serviceability-dev-bounces at openjdk.java.net> on behalf of chihiro ito <chihiro.ito at oracle.com>
>>>>>>>>> *Sent:* Wednesday, June 14, 2017 9:17:42 AM
>>>>>>>>> *To:* Jini George; serviceability-dev at openjdk.java.net
>>>>>>>>> *Subject:* Re: [10] RFR 8181647: jhsdb jstack could not output thread name
>>>>>>>>> Hi all,
>>>>>>>>>
>>>>>>>>> I added a test case and modified previous patch including fix the
>>>>>>>>> copyright year to 2017.
>>>>>>>>> I changed to output Java thread name next the separator lines in "jhsdb
>>>>>>>>> jstack --mixed" case as following.
>>>>>>>>>
>>>>>>>>> ----------------- 32117 -----------------
>>>>>>>>> "main"
>>>>>>>>> 0x00007f6c8feafa82    __pthread_cond_timedwait + 0x132
>>>>>>>>>
>>>>>>>>> Could you possibly review for this following small change? If review is
>>>>>>>>> ok, please commit this as cito.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Source:
>>>>>>>>> diff --git
>>>>>>>>> a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java
>>>>>>>>> b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java
>>>>>>>>> --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java
>>>>>>>>> +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java
>>>>>>>>> @@ -1,5 +1,5 @@
>>>>>>>>>   /*
>>>>>>>>> - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights
>>>>>>>>> reserved.
>>>>>>>>> + * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights
>>>>>>>>> reserved.
>>>>>>>>>    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>>>>>>>>>    *
>>>>>>>>>    * This code is free software; you can redistribute it and/or modify it
>>>>>>>>> @@ -88,6 +88,12 @@
>>>>>>>>>                  out.print("----------------- ");
>>>>>>>>>                  out.print(th);
>>>>>>>>>                  out.println(" -----------------");
>>>>>>>>> +               JavaThread jthread = (JavaThread) proxyToThread.get(th);
>>>>>>>>> +               if (jthread != null) {
>>>>>>>>> +                   out.print("\"");
>>>>>>>>> + out.print(jthread.getThreadName());
>>>>>>>>> +                   out.println("\"");
>>>>>>>>> +               }
>>>>>>>>>                  while (f != null) {
>>>>>>>>>                     ClosestSymbol sym = f.closestSymbolToPC();
>>>>>>>>>                     Address pc = f.pc();
>>>>>>>>> diff --git
>>>>>>>>> a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java
>>>>>>>>> b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java
>>>>>>>>> ---
>>>>>>>>> a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java
>>>>>>>>> +++
>>>>>>>>> b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java
>>>>>>>>> @@ -1,5 +1,5 @@
>>>>>>>>>   /*
>>>>>>>>> - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights
>>>>>>>>> reserved.
>>>>>>>>> + * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights
>>>>>>>>> reserved.
>>>>>>>>>    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>>>>>>>>>    *
>>>>>>>>>    * This code is free software; you can redistribute it and/or modify it
>>>>>>>>> @@ -75,7 +75,9 @@
>>>>>>>>>               for (JavaThread cur = threads.first(); cur != null; cur =
>>>>>>>>> cur.next(), i++) {
>>>>>>>>>                   if (cur.isJavaThread()) {
>>>>>>>>>                       Address sp = cur.getLastJavaSP();
>>>>>>>>> -                    tty.print("Thread ");
>>>>>>>>> +                    tty.print("\"");
>>>>>>>>> +                    tty.print(cur.getThreadName());
>>>>>>>>> +                    tty.print("\" nid=");
>>>>>>>>>                       cur.printThreadIDOn(tty);
>>>>>>>>>                       tty.print(": (state = " + cur.getThreadState());
>>>>>>>>>                       if (verbose) {
>>>>>>>>> diff --git a/test/serviceability/sa/JhsdbThreadNameTest.java
>>>>>>>>> b/test/serviceability/sa/JhsdbThreadNameTest.java
>>>>>>>>> new file mode 100644
>>>>>>>>> --- /dev/null
>>>>>>>>> +++ b/test/serviceability/sa/JhsdbThreadNameTest.java
>>>>>>>>> @@ -0,0 +1,107 @@
>>>>>>>>> +/*
>>>>>>>>> + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
>>>>>>>>> + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>>>>>>>>> + *
>>>>>>>>> + * This code is free software; you can redistribute it and/or modify it
>>>>>>>>> + * under the terms of the GNU General Public License version 2 only, as
>>>>>>>>> + * published by the Free Software Foundation.
>>>>>>>>> + *
>>>>>>>>> + * This code is distributed in the hope that it will be useful, but WITHOUT
>>>>>>>>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>>>>>>>>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
>>>>>>>>> + * version 2 for more details (a copy is included in the LICENSE file that
>>>>>>>>> + * accompanied this code).
>>>>>>>>> + *
>>>>>>>>> + * You should have received a copy of the GNU General Public License
>>>>>>>>> version
>>>>>>>>> + * 2 along with this work; if not, write to the Free Software Foundation,
>>>>>>>>> + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
>>>>>>>>> + *
>>>>>>>>> + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
>>>>>>>>> + * or visit www.oracle.com <http://www.oracle.com> if you need additional information or have any
>>>>>>>>> + * questions.
>>>>>>>>> + */
>>>>>>>>> +
>>>>>>>>> +import java.util.ArrayList;
>>>>>>>>> +import java.util.Arrays;
>>>>>>>>> +import java.util.List;
>>>>>>>>> +import java.util.function.Consumer;
>>>>>>>>> +
>>>>>>>>> +import jdk.test.lib.apps.LingeredApp;
>>>>>>>>> +import jdk.test.lib.JDKToolLauncher;
>>>>>>>>> +import jdk.test.lib.Platform;
>>>>>>>>> +import jdk.test.lib.process.OutputAnalyzer;
>>>>>>>>> +import jdk.test.lib.Utils;
>>>>>>>>> +
>>>>>>>>> +/*
>>>>>>>>> + * @test
>>>>>>>>> + * @library /test/lib
>>>>>>>>> + * @run main/othervm JhsdbThreadNameTest
>>>>>>>>> + */
>>>>>>>>> +public class JhsdbThreadNameTest {
>>>>>>>>> +
>>>>>>>>> +    private static String notMixedModeThreadNames[] =
>>>>>>>>> {"Common-Cleaner", "Signal Dispatcher", "Finalizer", "Reference
>>>>>>>>> Handler", "main"};
>>>>>>>>> +    private static String mixedModeThreadNames[] = {"C2
>>>>>>>>> CompilerThread0", "C1 CompilerThread1", "Sweeper thread", "Service Thread"};
>>>>>>>>> +
>>>>>>>>> +    private static void startHsdbJstack(boolean mixed) throws Exception {
>>>>>>>>> +
>>>>>>>>> +        LingeredApp app = null;
>>>>>>>>> +
>>>>>>>>> +        try {
>>>>>>>>> +            List<String> vmArgs = new ArrayList<String>();
>>>>>>>>> +            vmArgs.add("-Xmx10m");
>>>>>>>>> +            vmArgs.addAll(Utils.getVmOptions());
>>>>>>>>> +
>>>>>>>>> +            app = LingeredApp.startApp(vmArgs);
>>>>>>>>> +            System.out.println("Started LingeredApp with pid " +
>>>>>>>>> app.getPid());
>>>>>>>>> +
>>>>>>>>> +            JDKToolLauncher jhsdbLauncher =
>>>>>>>>> JDKToolLauncher.createUsingTestJDK("jhsdb");
>>>>>>>>> +
>>>>>>>>> +            jhsdbLauncher.addToolArg("jstack");
>>>>>>>>> +            jhsdbLauncher.addToolArg("--pid");
>>>>>>>>> + jhsdbLauncher.addToolArg(Long.toString(app.getPid()));
>>>>>>>>> +
>>>>>>>>> +            if (mixed) {
>>>>>>>>> + jhsdbLauncher.addToolArg("--mixed");
>>>>>>>>> +            }
>>>>>>>>> +            ProcessBuilder pb = new ProcessBuilder();
>>>>>>>>> +            pb.command(jhsdbLauncher.getCommand());
>>>>>>>>> +            Process jhsdb = pb.start();
>>>>>>>>> +
>>>>>>>>> +            jhsdb.waitFor();
>>>>>>>>> +
>>>>>>>>> +            OutputAnalyzer out = new OutputAnalyzer(jhsdb);
>>>>>>>>> +
>>>>>>>>> +
>>>>>>>>> Arrays.stream(notMixedModeThreadNames).map(JhsdbThreadNameTest::addQuotationMarks).forEach(out::shouldContain);
>>>>>>>>> +            Consumer<String> testMethod = null;
>>>>>>>>> +            if (mixed) {
>>>>>>>>> +                testMethod = out::shouldContain;
>>>>>>>>> +            } else {
>>>>>>>>> +                testMethod = out::shouldNotContain;
>>>>>>>>> +            }
>>>>>>>>> +
>>>>>>>>> Arrays.stream(mixedModeThreadNames).map(JhsdbThreadNameTest::addQuotationMarks).forEach(testMethod);
>>>>>>>>> +
>>>>>>>>> +        } catch (InterruptedException ie) {
>>>>>>>>> +            throw new Error("Problem awaiting the child process: " +
>>>>>>>>> ie, ie);
>>>>>>>>> +        } catch (Exception attachE) {
>>>>>>>>> +            throw new Error("Couldn't start jhsdb, attach to
>>>>>>>>> LingeredApp or match ThreadName: " + attachE);
>>>>>>>>> +
>>>>>>>>> +        } finally {
>>>>>>>>> +            LingeredApp.stopApp(app);
>>>>>>>>> +        }
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    private static String addQuotationMarks(String str) {
>>>>>>>>> +        return "\"" + str + "\"";
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    public static void main(String[] args) throws Exception {
>>>>>>>>> +
>>>>>>>>> +        if (!Platform.shouldSAAttach()) {
>>>>>>>>> +            System.out.println("SA attach not expected to work - test
>>>>>>>>> skipped.");
>>>>>>>>> +            return;
>>>>>>>>> +        }
>>>>>>>>> +
>>>>>>>>> +        startHsdbJstack(true);
>>>>>>>>> +        startHsdbJstack(false);
>>>>>>>>> +    }
>>>>>>>>> +}
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Regards,
>>>>>>>>> Chihiro
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On 2017/06/08 18:04, chihiro ito wrote:
>>>>>>>>> > Hi Jini,
>>>>>>>>> >
>>>>>>>>> > Thank you for your advices. I try to add the test case and modify the
>>>>>>>>> > copyright year to 2017.
>>>>>>>>> > Basically, I agree with your idea, but I think that the separator line
>>>>>>>>> > should finally be the same as the output of the jstack command. I
>>>>>>>>> > worry which is better way.
>>>>>>>>> >
>>>>>>>>> > Thanks,
>>>>>>>>> > Chihiro
>>>>>>>>> >
>>>>>>>>> > On 2017/06/08 16:42, Jini George wrote:
>>>>>>>>> >> Hi Chihiro,
>>>>>>>>> >>
>>>>>>>>> >> Thank you for making this useful change. Your changes look good.
>>>>>>>>> >>
>>>>>>>>> >> It would be great though if you could add a test case for this. Could
>>>>>>>>> >> you also modify the copyright year to 2017 ? One additional
>>>>>>>>> >> suggestion: The addition of the thread name makes the separator lines
>>>>>>>>> >> unaligned in the pstack/jstack --mixed cases. Like:
>>>>>>>>> >>
>>>>>>>>> >> ----------------- "Service Thread" nid=16051 -----------------
>>>>>>>>> >> and
>>>>>>>>> >> ----------------- nid=16052 -----------------
>>>>>>>>> >>
>>>>>>>>> >> So I am wondering if it would make sense to have the name printed out
>>>>>>>>> >> on a separate line to keep the separator lines aligned. But this is a
>>>>>>>>> >> nit, and I would leave it to you to decide on this.
>>>>>>>>> >>
>>>>>>>>> >> Thanks,
>>>>>>>>> >> Jini (Not a (R)eviewer)
>>>>>>>>> >>
>>>>>>>>> >> On 6/7/2017 3:16 PM, chihiro ito wrote:
>>>>>>>>> >>> Hi all,
>>>>>>>>> >>>
>>>>>>>>> >>> I changed to output Java thread name in jhsdb jstack as following.
>>>>>>>>> >>>
>>>>>>>>> >>> jhsdb jstack --pid 25879
>>>>>>>>> >>> "main" nid=25884: (state = BLOCKED)
>>>>>>>>> >>>
>>>>>>>>> >>> jhsdb jstack --mixed --pid 25879
>>>>>>>>> >>> ----------------- "main" nid=25884 -----------------
>>>>>>>>> >>>
>>>>>>>>> >>> Could you possibly review for this following small change? If review
>>>>>>>>> >>> is ok, please commit this as cito.
>>>>>>>>> >>>
>>>>>>>>> >>> Source:
>>>>>>>>> >>> diff --git
>>>>>>>>> >>> a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java
>>>>>>>>> >>> b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java
>>>>>>>>> >>> ---
>>>>>>>>> >>> a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java
>>>>>>>>> >>> +++
>>>>>>>>> >>> b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java
>>>>>>>>> >>> @@ -86,6 +86,13 @@
>>>>>>>>> >>>              try {
>>>>>>>>> >>>                 CFrame f = cdbg.topFrameForThread(th);
>>>>>>>>> >>> out.print("----------------- ");
>>>>>>>>> >>> +               JavaThread jthread = (JavaThread)
>>>>>>>>> >>> proxyToThread.get(th);
>>>>>>>>> >>> +               if (jthread != null) {
>>>>>>>>> >>> +                   out.print("\"");
>>>>>>>>> >>> + out.print(jthread.getThreadName());
>>>>>>>>> >>> +                   out.print("\" ");
>>>>>>>>> >>> +               }
>>>>>>>>> >>> +               out.print("nid=");
>>>>>>>>> >>>                 out.print(th);
>>>>>>>>> >>>                 out.println(" -----------------");
>>>>>>>>> >>>                 while (f != null) {
>>>>>>>>> >>> diff --git
>>>>>>>>> >>> a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java
>>>>>>>>> >>> b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java
>>>>>>>>> >>>
>>>>>>>>> >>> ---
>>>>>>>>> >>> a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java
>>>>>>>>> >>> +++
>>>>>>>>> >>> b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/StackTrace.java
>>>>>>>>> >>> @@ -75,7 +75,9 @@
>>>>>>>>> >>>              for (JavaThread cur = threads.first(); cur != null; cur
>>>>>>>>> >>> = cur.next(), i++) {
>>>>>>>>> >>>                  if (cur.isJavaThread()) {
>>>>>>>>> >>>                      Address sp = cur.getLastJavaSP();
>>>>>>>>> >>> -                    tty.print("Thread ");
>>>>>>>>> >>> +                    tty.print("\"");
>>>>>>>>> >>> + tty.print(cur.getThreadName());
>>>>>>>>> >>> +                    tty.print("\" nid=");
>>>>>>>>> >>> cur.printThreadIDOn(tty);
>>>>>>>>> >>>                      tty.print(": (state = " + cur.getThreadState());
>>>>>>>>> >>>                      if (verbose) {
>>>>>>>>> >>>
>>>>>>>>> >>> Regards,
>>>>>>>>> >>> Chihiro
>>>>>>>>> >>>
>>>>>>>>> >>
>>>>>>>>> >
>>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>
>>>
>


More information about the serviceability-dev mailing list