1 /*
   2  * Copyright (c) 2000, 2013, 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.runtime;
  26 
  27 import java.util.*;
  28 
  29 import sun.jvm.hotspot.debugger.*;
  30 import sun.jvm.hotspot.types.*;
  31 import sun.jvm.hotspot.runtime.solaris_sparc.SolarisSPARCJavaThreadPDAccess;
  32 import sun.jvm.hotspot.runtime.solaris_x86.SolarisX86JavaThreadPDAccess;
  33 import sun.jvm.hotspot.runtime.solaris_amd64.SolarisAMD64JavaThreadPDAccess;
  34 import sun.jvm.hotspot.runtime.win32_amd64.Win32AMD64JavaThreadPDAccess;
  35 import sun.jvm.hotspot.runtime.win32_x86.Win32X86JavaThreadPDAccess;
  36 import sun.jvm.hotspot.runtime.linux_x86.LinuxX86JavaThreadPDAccess;
  37 import sun.jvm.hotspot.runtime.linux_amd64.LinuxAMD64JavaThreadPDAccess;
  38 import sun.jvm.hotspot.runtime.linux_ppc64.LinuxPPC64JavaThreadPDAccess;
  39 import sun.jvm.hotspot.runtime.linux_sparc.LinuxSPARCJavaThreadPDAccess;
  40 import sun.jvm.hotspot.runtime.bsd_x86.BsdX86JavaThreadPDAccess;
  41 import sun.jvm.hotspot.runtime.bsd_amd64.BsdAMD64JavaThreadPDAccess;
  42 import sun.jvm.hotspot.utilities.*;
  43 
  44 public class Threads {
  45     private static JavaThreadFactory threadFactory;
  46     private static AddressField      threadListField;
  47     private static CIntegerField     numOfThreadsField;
  48     private static VirtualConstructor virtualConstructor;
  49     private static JavaThreadPDAccess access;
  50 
  51     static {
  52         VM.registerVMInitializedObserver(new Observer() {
  53             public void update(Observable o, Object data) {
  54                 initialize(VM.getVM().getTypeDataBase());
  55             }
  56         });
  57     }
  58 
  59     private static synchronized void initialize(TypeDataBase db) {
  60         Type type = db.lookupType("Threads");
  61 
  62         threadListField = type.getAddressField("_thread_list");
  63         numOfThreadsField = type.getCIntegerField("_number_of_threads");
  64 
  65         // Instantiate appropriate platform-specific JavaThreadFactory
  66         String os  = VM.getVM().getOS();
  67         String cpu = VM.getVM().getCPU();
  68 
  69         access = null;
  70         // FIXME: find the platform specific PD class by reflection?
  71         if (os.equals("solaris")) {
  72             if (cpu.equals("sparc")) {
  73                 access = new SolarisSPARCJavaThreadPDAccess();
  74             } else if (cpu.equals("x86")) {
  75                 access = new SolarisX86JavaThreadPDAccess();
  76             } else if (cpu.equals("amd64")) {
  77                 access = new SolarisAMD64JavaThreadPDAccess();
  78             }
  79         } else if (os.equals("win32")) {
  80             if (cpu.equals("x86")) {
  81                 access =  new Win32X86JavaThreadPDAccess();
  82             } else if (cpu.equals("amd64")) {
  83                 access =  new Win32AMD64JavaThreadPDAccess();
  84             }
  85         } else if (os.equals("linux")) {
  86             if (cpu.equals("x86")) {
  87                 access = new LinuxX86JavaThreadPDAccess();
  88             } else if (cpu.equals("amd64")) {
  89                 access = new LinuxAMD64JavaThreadPDAccess();
  90             } else if (cpu.equals("sparc")) {
  91                 access = new LinuxSPARCJavaThreadPDAccess();
  92             } else if (cpu.equals("ppc64")) {
  93                 access = new LinuxPPC64JavaThreadPDAccess();
  94             } else {
  95               try {
  96                 access = (JavaThreadPDAccess)
  97                   Class.forName("sun.jvm.hotspot.runtime.linux_" +
  98                      cpu.toLowerCase() + ".Linux" + cpu.toUpperCase() +
  99                      "JavaThreadPDAccess").newInstance();
 100               } catch (Exception e) {
 101                 throw new RuntimeException("OS/CPU combination " + os + "/" + cpu +
 102                                            " not yet supported");
 103               }
 104             }
 105         } else if (os.equals("bsd")) {
 106             if (cpu.equals("x86")) {
 107                 access = new BsdX86JavaThreadPDAccess();
 108             } else if (cpu.equals("amd64") || cpu.equals("x86_64")) {
 109                 access = new BsdAMD64JavaThreadPDAccess();
 110             }
 111         } else if (os.equals("darwin")) {
 112             if (cpu.equals("amd64") || cpu.equals("x86_64")) {
 113                 access = new BsdAMD64JavaThreadPDAccess();
 114             }
 115         }
 116 
 117         if (access == null) {
 118             throw new RuntimeException("OS/CPU combination " + os + "/" + cpu +
 119             " not yet supported");
 120         }
 121 
 122         virtualConstructor = new VirtualConstructor(db);
 123         // Add mappings for all known thread types
 124         virtualConstructor.addMapping("JavaThread", JavaThread.class);
 125         if (!VM.getVM().isCore()) {
 126             virtualConstructor.addMapping("CompilerThread", CompilerThread.class);
 127             virtualConstructor.addMapping("CodeCacheSweeperThread", CodeCacheSweeperThread.class);
 128         }
 129         // for now, use JavaThread itself. fix it later with appropriate class if needed
 130         virtualConstructor.addMapping("SurrogateLockerThread", JavaThread.class);
 131         virtualConstructor.addMapping("JvmtiAgentThread", JvmtiAgentThread.class);
 132         virtualConstructor.addMapping("ServiceThread", ServiceThread.class);
 133     }
 134 
 135     public Threads() {
 136     }
 137 
 138     /** NOTE: this returns objects of type JavaThread, CompilerThread,
 139       JvmtiAgentThread, and ServiceThread.
 140       The latter four are subclasses of the former. Most operations
 141       (fetching the top frame, etc.) are only allowed to be performed on
 142       a "pure" JavaThread. For this reason, {@link
 143       sun.jvm.hotspot.runtime.JavaThread#isJavaThread} has been
 144       changed from the definition in the VM (which returns true for
 145       all of these thread types) to return true for JavaThreads and
 146       false for the three subclasses. FIXME: should reconsider the
 147       inheritance hierarchy; see {@link
 148       sun.jvm.hotspot.runtime.JavaThread#isJavaThread}. */
 149     public JavaThread first() {
 150         Address threadAddr = threadListField.getValue();
 151         if (threadAddr == null) {
 152             return null;
 153         }
 154 
 155         return createJavaThreadWrapper(threadAddr);
 156     }
 157 
 158     public int getNumberOfThreads() {
 159         return (int) numOfThreadsField.getValue();
 160     }
 161 
 162     /** Routine for instantiating appropriately-typed wrapper for a
 163       JavaThread. Currently needs to be public for OopUtilities to
 164       access it. */
 165     public JavaThread createJavaThreadWrapper(Address threadAddr) {
 166         try {
 167             JavaThread thread = (JavaThread)virtualConstructor.instantiateWrapperFor(threadAddr);
 168             thread.setThreadPDAccess(access);
 169             return thread;
 170         } catch (Exception e) {
 171             throw new RuntimeException("Unable to deduce type of thread from address " + threadAddr +
 172             " (expected type JavaThread, CompilerThread, ServiceThread, JvmtiAgentThread, SurrogateLockerThread, or CodeCacheSweeperThread)", e);
 173         }
 174     }
 175 
 176     /** Memory operations */
 177     public void oopsDo(AddressVisitor oopVisitor) {
 178         // FIXME: add more of VM functionality
 179         for (JavaThread thread = first(); thread != null; thread = thread.next()) {
 180             thread.oopsDo(oopVisitor);
 181         }
 182     }
 183 
 184     // refer to Threads::owning_thread_from_monitor_owner
 185     public JavaThread owningThreadFromMonitor(Address o) {
 186         if (o == null) return null;
 187         for (JavaThread thread = first(); thread != null; thread = thread.next()) {
 188             if (o.equals(thread.threadObjectAddress())) {
 189                 return thread;
 190             }
 191         }
 192 
 193         for (JavaThread thread = first(); thread != null; thread = thread.next()) {
 194           if (thread.isLockOwned(o))
 195             return thread;
 196         }
 197         return null;
 198     }
 199 
 200     public JavaThread owningThreadFromMonitor(ObjectMonitor monitor) {
 201         return owningThreadFromMonitor(monitor.owner());
 202     }
 203 
 204     // refer to Threads::get_pending_threads
 205     // Get list of Java threads that are waiting to enter the specified monitor.
 206     public List getPendingThreads(ObjectMonitor monitor) {
 207         List pendingThreads = new ArrayList();
 208         for (JavaThread thread = first(); thread != null; thread = thread.next()) {
 209             if (thread.isCompilerThread() || thread.isCodeCacheSweeperThread()) {
 210                 continue;
 211             }
 212             ObjectMonitor pending = thread.getCurrentPendingMonitor();
 213             if (monitor.equals(pending)) {
 214                 pendingThreads.add(thread);
 215             }
 216         }
 217         return pendingThreads;
 218     }
 219 
 220     // Get list of Java threads that have called Object.wait on the specified monitor.
 221     public List getWaitingThreads(ObjectMonitor monitor) {
 222         List pendingThreads = new ArrayList();
 223         for (JavaThread thread = first(); thread != null; thread = thread.next()) {
 224             ObjectMonitor waiting = thread.getCurrentWaitingMonitor();
 225             if (monitor.equals(waiting)) {
 226                 pendingThreads.add(thread);
 227             }
 228         }
 229         return pendingThreads;
 230     }
 231 
 232     // FIXME: add other accessors
 233 }