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

chihiro ito chihiro.ito at oracle.com
Wed Jul 5 19:58:27 UTC 2017


Hello Poonam,

Thank you for reviewing.

I applyed your advices. The webrev is following.

http://cr.openjdk.java.net/~dbuck/8181647.1/

Could you review, please?

Regards,
Chihiro

On 2017/07/06 3:23, Poonam Parhar wrote:
> Hello Chihiro,
>
> The changes in the following webrev look good to me:
> http://cr.openjdk.java.net/~dbuck/8181647.0/
>
> A few minor suggestions though:
>
> - src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/OopUtilities.java
>
> Lines 354 - 370:
> Extra whitespace in the if conditions can be removed:
> if( status == THREAD_STATUS_NEW ){
> to
> if(status == THREAD_STATUS_NEW){
>
> please do this for all the 'if' statements.
>
> - share/classes/sun/jvm/hotspot/runtime/JavaThread.java.
> Line 482: extra line; can be removed
> Line 507: not indented properly
>
> Thanks,
> Poonam
>
>
>> -----Original Message-----
>> From: Yasumasa Suenaga [mailto:yasuenag at gmail.com]
>> Sent: Tuesday, July 04, 2017 3:44 PM
>> To: chihiro ito
>> Cc: serviceability-dev at openjdk.java.net
>> Subject: Re: [10] RFR 8181647: jhsdb jstack could not output thread
>> name
>>
>> 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").intV
>> alue();
>>> -        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").intV
>> alue();
>>> +      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/JavaThrea
>> d.java
>> b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThrea
>> d.java
>>> ---
>> a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThrea
>> d.java
>>> +++
>> b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThrea
>> d.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/ThreadSta
>> te.java
>> b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadSta
>> te.java
>>> new file mode 100644
>>> --- /dev/null
>>> +++
>> b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadSta
>> te.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").intV
>> alue();
>>>>> -        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").intV
>> alue();
>>>>> +      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/JavaThrea
>> d.java
>> b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThrea
>> d.java
>>>>> ---
>> a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThrea
>> d.java
>>>>> +++
>> b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThrea
>> d.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/ThreadSta
>> te.java
>> b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadSta
>> te.java
>>>>> new file mode 100644
>>>>> --- /dev/null
>>>>> +++
>> b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadSta
>> te.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").intV
>> alue();
>>>>>>> -        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").intV
>> alue();
>>>>>>> +      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/JavaThrea
>> d.java
>> b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThrea
>> d.java
>>>>>>> ---
>> a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThrea
>> d.java
>>>>>>> +++
>> b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThrea
>> d.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/ThreadSta
>> te.java
>> b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadSta
>> te.java
>>>>>>> new file mode 100644
>>>>>>> --- /dev/null
>>>>>>> +++
>> b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadSta
>> te.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").intV
>> alue();
>>>>>>>>>> -        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").intV
>> alue();
>>>>>>>>>> +      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/JavaThrea
>> d.java
>> b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThrea
>> d.java
>>>>>>>>>> ---
>> a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThrea
>> d.java
>>>>>>>>>> +++
>> b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThrea
>> d.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/ThreadSta
>> te.java
>> b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadSta
>> te.java
>>>>>>>>>> new file mode 100644
>>>>>>>>>> --- /dev/null
>>>>>>>>>> +++
>> b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadSta
>> te.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=RoP1YumCXCgaWHvlZYR8PQcxBKCX5YTpkKY0
>> 57SbK10&r=0SCyhNQIV2jPt0aEruqsRB6bzVcIXHTDh1GkXLV1dyY&m=3QRaQqXxp0PcpNU
>> QsiJOAlmzxeN3O9PyZoFxlIPpsUs&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::addQuot
>> ationMarks).forEach(out::shouldContain);
>>>>>>>>>>> +            Consumer<String> testMethod = null;
>>>>>>>>>>> +            if (mixed) {
>>>>>>>>>>> +                testMethod = out::shouldContain;
>>>>>>>>>>> +            } else {
>>>>>>>>>>> +                testMethod = out::shouldNotContain;
>>>>>>>>>>> +            }
>>>>>>>>>>> +
>>>>>>>>>>>
>> Arrays.stream(mixedModeThreadNames).map(JhsdbThreadNameTest::addQuotati
>> onMarks).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
>>>>>>>>>>>>>>

-- 
Chihiro Ito @Oracle Consulting


More information about the serviceability-dev mailing list