hotspot/agent/src/share/classes/sun/jvm/hotspot/bugspot/ThreadListPanel.java
changeset 15832 6c7a82c0b538
parent 15831 18835185e71e
parent 15830 f89fb3fb1554
child 15834 89c34ec6d638
equal deleted inserted replaced
15831:18835185e71e 15832:6c7a82c0b538
     1 /*
       
     2  * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  *
       
    23  */
       
    24 
       
    25 package sun.jvm.hotspot.bugspot;
       
    26 
       
    27 import java.awt.*;
       
    28 import java.awt.event.*;
       
    29 import java.util.*;
       
    30 import javax.swing.*;
       
    31 import javax.swing.table.*;
       
    32 
       
    33 import sun.jvm.hotspot.debugger.*;
       
    34 import sun.jvm.hotspot.debugger.cdbg.*;
       
    35 import sun.jvm.hotspot.runtime.*;
       
    36 import sun.jvm.hotspot.ui.*;
       
    37 
       
    38 // NOTE: this class was not placed in sun.jvm.hotspot.ui to prevent
       
    39 // mixing components designed for C and C++ debugging with the ones
       
    40 // that work with the core serviceability agent functionality (which
       
    41 // does not require that the CDebugger interface be implemented).
       
    42 
       
    43 /** The ThreadListPanel is used for C and C++ debugging and can
       
    44     visualize all threads in the target process. The caller passes in
       
    45     a CDebugger attached to the target process and can request that
       
    46     JavaThreads' associations with these underlying threads be
       
    47     displayed; this option is only valid when attached to a HotSpot
       
    48     JVM and when the {@link sun.jvm.hotspot.runtime.VM} has been
       
    49     initialized. */
       
    50 
       
    51 public class ThreadListPanel extends JPanel {
       
    52   /** Listener which can be added to receive "Set Focus" events */
       
    53   public static interface Listener {
       
    54     /** ThreadProxy will always be provided; JavaThread will only be
       
    55         present if displayJavaThreads was specified in the constructor
       
    56         for the panel and the thread was a JavaThread. */
       
    57     public void setFocus(ThreadProxy thread, JavaThread jthread);
       
    58   }
       
    59 
       
    60   static class ThreadInfo {
       
    61     private ThreadProxy thread;
       
    62     // Distinguish between PC == null and no top frame
       
    63     private boolean     gotPC;
       
    64     private Address     pc;
       
    65     private String      location;
       
    66     private JavaThread  javaThread;
       
    67     private String      javaThreadName;
       
    68 
       
    69     public ThreadInfo(ThreadProxy thread, CDebugger dbg, JavaThread jthread) {
       
    70       this.thread = thread;
       
    71       this.location = "<unknown>";
       
    72       CFrame fr = dbg.topFrameForThread(thread);
       
    73       if (fr != null) {
       
    74         gotPC = true;
       
    75         pc = fr.pc();
       
    76         PCFinder.Info info = PCFinder.findPC(pc, fr.loadObjectForPC(), dbg);
       
    77         if (info.getName() != null) {
       
    78           location = info.getName();
       
    79           if (info.getConfidence() == PCFinder.LOW_CONFIDENCE) {
       
    80             location = location + " (?)";
       
    81           }
       
    82           if (info.getOffset() < 0) {
       
    83             location = location + " + 0x" + Long.toHexString(info.getOffset());
       
    84           }
       
    85         }
       
    86       }
       
    87       if (jthread != null) {
       
    88         javaThread = jthread;
       
    89         javaThreadName = jthread.getThreadName();
       
    90       }
       
    91     }
       
    92 
       
    93     public ThreadProxy getThread()    { return thread;       }
       
    94     public boolean     hasPC()        { return gotPC;        }
       
    95     public Address     getPC()        { return pc;           }
       
    96     public String      getLocation()  { return location;     }
       
    97     public boolean     isJavaThread() { return (javaThread != null); }
       
    98     public JavaThread  getJavaThread() { return javaThread; }
       
    99     public String      getJavaThreadName() { return javaThreadName; }
       
   100   }
       
   101 
       
   102   // List<ThreadInfo>
       
   103   private java.util.List threadList;
       
   104   private JTable table;
       
   105   private AbstractTableModel dataModel;
       
   106   // List<Listener>
       
   107   private java.util.List listeners;
       
   108 
       
   109   /** Takes a CDebugger from which the thread list is queried.
       
   110       displayJavaThreads must only be set to true if the debugger is
       
   111       attached to a HotSpot JVM and if the VM has already been
       
   112       initialized. */
       
   113   public ThreadListPanel(CDebugger dbg, final boolean displayJavaThreads) {
       
   114     super();
       
   115 
       
   116     Map threadToJavaThreadMap = null;
       
   117     if (displayJavaThreads) {
       
   118       // Collect Java threads from virtual machine and insert them in
       
   119       // table for later querying
       
   120       threadToJavaThreadMap = new HashMap();
       
   121       Threads threads = VM.getVM().getThreads();
       
   122       for (JavaThread thr = threads.first(); thr != null; thr = thr.next()) {
       
   123         threadToJavaThreadMap.put(thr.getThreadProxy(), thr);
       
   124       }
       
   125     }
       
   126 
       
   127     java.util.List/*<ThreadProxy>*/ threads = dbg.getThreadList();
       
   128     threadList = new ArrayList(threads.size());
       
   129     for (Iterator iter = threads.iterator(); iter.hasNext(); ) {
       
   130       ThreadProxy thr = (ThreadProxy) iter.next();
       
   131       JavaThread jthr = null;
       
   132       if (displayJavaThreads) {
       
   133         jthr = (JavaThread) threadToJavaThreadMap.get(thr);
       
   134       }
       
   135       threadList.add(new ThreadInfo(thr, dbg, jthr));
       
   136     }
       
   137 
       
   138     // Thread ID, current PC, current symbol, Java Thread, [Java thread name]
       
   139     dataModel = new AbstractTableModel() {
       
   140         public int getColumnCount() { return (displayJavaThreads ? 5 : 3); }
       
   141         public int getRowCount()    { return threadList.size(); }
       
   142         public String getColumnName(int col) {
       
   143           switch (col) {
       
   144           case 0:
       
   145             return "Thread ID";
       
   146           case 1:
       
   147             return "PC";
       
   148           case 2:
       
   149             return "Location";
       
   150           case 3:
       
   151             return "Java?";
       
   152           case 4:
       
   153             return "Java Thread Name";
       
   154           default:
       
   155             throw new RuntimeException("Index " + col + " out of bounds");
       
   156           }
       
   157         }
       
   158         public Object getValueAt(int row, int col) {
       
   159           ThreadInfo info = (ThreadInfo) threadList.get(row);
       
   160 
       
   161           switch (col) {
       
   162           case 0:
       
   163             return info.getThread();
       
   164           case 1:
       
   165             {
       
   166               if (info.hasPC()) {
       
   167                 return info.getPC();
       
   168               }
       
   169               return "<no frames on stack>";
       
   170             }
       
   171           case 2:
       
   172             return info.getLocation();
       
   173           case 3:
       
   174             if (info.isJavaThread()) {
       
   175               return "Yes";
       
   176             } else {
       
   177               return "";
       
   178             }
       
   179           case 4:
       
   180             if (info.isJavaThread()) {
       
   181               return info.getJavaThreadName();
       
   182             } else {
       
   183               return "";
       
   184             }
       
   185           default:
       
   186             throw new RuntimeException("Index (" + col + ", " + row + ") out of bounds");
       
   187           }
       
   188         }
       
   189       };
       
   190 
       
   191     // Build user interface
       
   192     setLayout(new BorderLayout());
       
   193     table = new JTable(dataModel);
       
   194     table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
       
   195     JTableHeader header = table.getTableHeader();
       
   196     header.setReorderingAllowed(false);
       
   197     table.setRowSelectionAllowed(true);
       
   198     table.setColumnSelectionAllowed(false);
       
   199     JScrollPane scrollPane = new JScrollPane(table);
       
   200     add(scrollPane, BorderLayout.CENTER);
       
   201     if (threadList.size() > 0) {
       
   202       table.setRowSelectionInterval(0, 0);
       
   203     }
       
   204 
       
   205     JButton button = new JButton("Set Focus");
       
   206     button.addActionListener(new ActionListener() {
       
   207         public void actionPerformed(ActionEvent e) {
       
   208           int i = table.getSelectedRow();
       
   209           if (i < 0) {
       
   210             return;
       
   211           }
       
   212           ThreadInfo info = (ThreadInfo) threadList.get(i);
       
   213           for (Iterator iter = listeners.iterator(); iter.hasNext(); ) {
       
   214             ((Listener) iter.next()).setFocus(info.getThread(), info.getJavaThread());
       
   215           }
       
   216         }
       
   217       });
       
   218     JPanel focusPanel = new JPanel();
       
   219     focusPanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0));
       
   220     focusPanel.setLayout(new BoxLayout(focusPanel, BoxLayout.Y_AXIS));
       
   221     focusPanel.add(Box.createGlue());
       
   222     focusPanel.add(button);
       
   223     focusPanel.add(Box.createGlue());
       
   224     add(focusPanel, BorderLayout.EAST);
       
   225 
       
   226     // FIXME: make listener model for the debugger so if the user
       
   227     // specifies a mapfile for or path to a given DSO later we can
       
   228     // update our state
       
   229   }
       
   230 
       
   231   public void addListener(Listener l) {
       
   232     if (listeners == null) {
       
   233       listeners = new ArrayList();
       
   234     }
       
   235     listeners.add(l);
       
   236   }
       
   237 }