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