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 }