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

Yasumasa Suenaga yasuenag at gmail.com
Sun Jul 2 12:44:30 UTC 2017


Hi Chihiro,


printThreadInfoOn() in JavaThread.java:
> +      Address maskAddress = this.getLastJavaSP().andWithMask(0xFFF);
> + out.print(this.getLastJavaSP().xorWithMask(maskAddress.asLongValue()));

IMHO it is complex a bit.
According to JavaThread::print_on() in thread.cpp , stack address in thread dump shows top of page address.
If so, can we calculate it as below?

   this.getLastJavaSP().andWithMask(~0xFFF)


JhsdbThreadInfoTest.java:
> +            out.shouldMatch("\".+\" #\\d+ daemon prio=\\d+ tid=0x[0-9a-f]+ nid=0x[0-9a-f]+ .+ \\[0x[0-9a-f]+]");
> +            out.shouldMatch("\"main\" #\\d+ prio=\\d+ tid=0x[0-9a-f]+ nid=0x[0-9a-f]+ .+ \\[0x[0-9a-f]+]");

Are these regex correct?
Regex for SP "\\[0x[0-9a-f]+]" should be "\\[0x[0-9a-f]+\\]"
(Last backslash is missing.)


Thanks,

Yasumasa


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


More information about the serviceability-dev mailing list