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