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