-----Original Message-----
From: chihiro ito
Sent: Wednesday, July 05, 2017 12:58 PM
To: Poonam Parhar; Yasumasa Suenaga
Cc: serviceability-dev@openjdk.java.net
Subject: Re: [10] RFR 8181647: jhsdb jstack could not output thread
name
Hello Poonam,
Thank you for reviewing.
I applyed your advices. The webrev is following.
http://cr.openjdk.java.net/~dbuck/8181647.1/
Could you review, please?
Regards,
Chihiro
On 2017/07/06 3:23, Poonam Parhar wrote:
Hello Chihiro,
The changes in the following webrev look good to me:
http://cr.openjdk.java.net/~dbuck/8181647.0/
A few minor suggestions though:
-
src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/OopUtilities.j
ava
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
--
Chihiro Ito @Oracle Consulting