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:yasue...@gmail.com] > Sent: Tuesday, July 04, 2017 3:44 PM > To: chihiro ito > Cc: serviceability-dev@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- > boun...@openjdk.java.net> on behalf of chihiro ito > <chihiro....@oracle.com> > >>>>>>>>> *Sent:* Wednesday, June 14, 2017 9:17:42 AM > >>>>>>>>> *To:* Jini George; serviceability-dev@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 > >>>>>>>>> >>> > >>>>>>>>> >> > >>>>>>>>> > > >>>>>>>>> > >>>>>>>> > >>>>>>> > >>>>> > >>> > >